You're trying to start a local server or dev tool and hitting this error
It's frustrating. You run your Node.js app, your Python Flask dev server, or a local web service, and it fails with WSAEADDRINUSE (0X00002740). The message says Only one usage of each socket address is normally permitted. That's Windows telling you: the port you want is already owned by another process.
Skip the rabbit hole of firewall settings, antivirus blocks, or reinstalling tools. The real fix is simpler than you think. Here's how to resolve it in under two minutes.
Step-by-step fix – Find and kill the process using your port
- Open Command Prompt as Administrator – Press Win, type
cmd, right-click and select Run as administrator. You'll need admin rights to kill system-level processes. - Find what's using your port – Replace
8080with whatever port your app is trying to bind to. Run this:
You'll see output like:netstat -ano | findstr :8080
The number at the end (in this caseTCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 1234512345) is the process ID (PID) of the owning process. - Kill that process – Use the PID from the previous step:
Thetaskkill /PID 12345 /F/Fflag forces termination. If it says Access denied, you weren't running as administrator – go back to step 1. - Verify the port is free – Run the
netstatcommand again. If it returns nothing, the port is clear. Start your app again.
Why this works – The OS tracks every socket by (protocol, IP, port)
What's actually happening here is the Windows TCP/IP stack enforces a fundamental rule: each socket tuple – that's (protocol, local IP, local port) – must be unique. When your app calls bind() with a port, the kernel checks if that tuple is already in use. If it is, you get WSAEADDRINUSE.
This isn't a bug. It's by design. Without this check, two processes could receive data meant for the other. The fix above simply removes the offender.
Less common variations – When the simple kill doesn't work
1. TIME_WAIT state – The port is lingering
If netstat shows your port in TIME_WAIT state (not LISTENING), the owning process has already exited, but the socket is held by the kernel for 2–4 minutes. This is a normal TCP behavior to handle delayed packets. You can either wait it out or set the SO_REUSEADDR socket option in your app code. In Python: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1). In Node.js: server.listen(port, '0.0.0.0', () => { ... }) doesn't help by itself; you need to set the option before bind(). Use net.Server({ reuseAddr: true }).
2. System process – PID 4 or svchost.exe
Sometimes the port is used by a system service like PID 4 (the NT Kernel) or svchost.exe. Killing system processes is risky and often fails. The real cause is often the World Wide Web Publishing Service (W3SVC) or SQL Server Reporting Services binding to port 80 or 8080. Fix this by stopping the specific service: net stop W3SVC (if you're not using IIS) or net stop MSSQLSERVER (if SQL Server is on that port).
3. Hyper-V reserved ports – Windows 10/11 issue
On Windows 10 version 1803 and later, Hyper-V can reserve a range of ports, blocking your app even when no process is listed. Check with: netsh int ipv4 show excludedportrange protocol=tcp. If your port falls in a reserved range, you can either pick a different port or disable the dynamic port range reservation (requires a reboot after running netsh int ipv4 set dynamic tcp start=10000 num=50000) – but that's a nuclear option. I'd just pick a different port.
Prevention – Stop this from coming back
- Always set SO_REUSEADDR in your development server code. It allows binding to a port in TIME_WAIT state. This doesn't fix a port held by a running process, but it does prevent the most common recurrence after a restart.
- Use dynamic ports during development – If your framework supports it, use port 0 to let the OS assign a random free port. In Node.js with Express: don't hardcode the port; read it from
process.env.PORTor fallback to0. - Graceful shutdown – Always handle SIGTERM/SIGINT in your app to close the socket cleanly. A dangling socket that didn't close triggers TIME_WAIT. For Python:
atexit.register(s.close). For Node.js:process.on('SIGINT', () => server.close()).
That's it. Next time you see WSAEADDRINUSE, you know exactly where to look – and what to do.