You fire up your server and Windows throws:
Only one usage of each socket address (protocol/network address/port) is normally permitted
This is Windows' equivalent of EADDRINUSE on Linux. A TCP port can only be bound by one process at a time โ and something else already owns yours. Your app won't start until that port is freed.
Root cause
Three things cause this. Usually it's one of:
- A previous instance of your app crashed or wasn't shut down cleanly, leaving the port locked
- A system service (IIS, SQL Server, Apache, Hyper-V virtual switch) grabbed the port at Windows startup
- Windows itself reserved the port range โ this happens after enabling Hyper-V, WSL2, or Docker Desktop
Step 1: Find which process owns the port
Open Command Prompt as Administrator and run:
netstat -ano | findstr :3000
Replace 3000 with your actual port number. Output looks like:
TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 12345
The last column is the PID (Process ID). To see the program behind it:
tasklist /FI "PID eq 12345"
Sample output:
Image Name PID Session Name Session# Mem Usage
========================= ======== ================ =========== ============
node.exe 12345 Console 1 52,340 K
Now you know exactly what's holding the port.
Step 2: Kill the process
taskkill /PID 12345 /F
The /F flag forces immediate termination. Getting Access is denied? You need an elevated prompt โ right-click the Start menu and choose Windows Terminal (Admin) or Command Prompt (Admin).
PowerShell one-liner
Prefer PowerShell? This finds and kills the process in a single command:
Stop-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess -Force
Want to preview what you're about to kill before committing:
Get-NetTCPConnection -LocalPort 3000 | Select-Object LocalPort, OwningProcess,
@{n='ProcessName'; e={(Get-Process -Id $_.OwningProcess).Name}}
Sample output:
LocalPort OwningProcess ProcessName
--------- ------------- -----------
3000 12345 node
Special case: Windows reserved port ranges
After enabling Hyper-V, WSL2, or Docker Desktop, Windows reserves blocks of dynamic ports at boot. When your port falls inside a reserved block, killing processes won't help โ the OS is blocking it at the network stack level.
Check which ports Windows has reserved:
netsh interface ipv4 show excludedportrange protocol=tcp
Spot your port in the output? Switch to a port outside the reserved ranges. Or reset the dynamic port range entirely:
netsh int ipv4 set dynamicport tcp start=49152 num=16384
Restart Windows after changing this. One thing worth knowing: Hyper-V and Docker don't only touch the 49152โ65535 range โ they can reserve blocks in the 5000โ9000 range too. Always verify against the actual netsh output on your machine rather than assuming a port is free.
Step 3: Verify the fix
After killing the process, confirm the port is free:
netstat -ano | findstr :3000
No output means the port is available. Start your server โ it should bind without errors this time.
Still seeing a TIME_WAIT entry instead of nothing?
TCP 0.0.0.0:3000 0.0.0.0:0 TIME_WAIT 0
That's a recently closed connection still draining. Wait 30โ60 seconds and retry, or switch to a different port temporarily.
Prevention
If this keeps recurring because your app crashes mid-run without releasing the port:
- Node.js: Handle
SIGTERM/SIGINTexplicitly to close the HTTP server before exiting. Running underpm2also helps โ it manages restarts and cleanup automatically. - Python: Set
SO_REUSEADDRon your socket before callingbind(). Flask's dev server does this by default; Gunicorn handles it correctly in production too. - Java / .NET: Add a shutdown hook that calls
server.close()โ or the framework equivalent โ so the port gets released on exit, even on crashes.
Before hardcoding any port in your config, check what's already in use:
netstat -ano | findstr LISTENING
Developer machines often have SQL Server (1433), IIS (80/443), and PostgreSQL (5432) running quietly in the background. Picking a port that's already taken just delays the problem to runtime.

