Freeing a port on Windows when localhost:3000 is already in use
A dev server that did not shut down cleanly keeps holding its port. Two commands find the process behind the port on Windows and kill it.
You start a dev server and it refuses to run because the port is taken:
Error: listen EADDRINUSE: address already in use :::3000
Usually nothing visible is using it. An earlier server is still running in the background, because a terminal was closed without stopping it, an editor crashed, or a process hung on exit. It keeps the port until you end it.
On Windows, two commands fix this: one finds the process ID that holds the port, the other kills it.
The fix#
Open Command Prompt or PowerShell. Replace 3000 with your port.
1. Find the process using the port#
netstat -ano | findstr :3000
The output looks something like this:
TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 18244
TCP [::]:3000 [::]:0 LISTENING 18244
Find the line with :3000 in the second column (the local address) and the state LISTENING. The number in the last column is the process ID (PID), here 18244. The IPv4 and IPv6 lines usually show the same PID.
2. Kill it#
taskkill /PID 18244 /F
If it works, you see:
SUCCESS: The process with PID 18244 has been terminated.
The port is free, and the dev server will start again.
What the flags mean#
| Command | What it does |
|---|---|
netstat -a |
Lists all connections and listening ports. |
netstat -n |
Shows addresses and ports as numbers instead of resolving names, which is much faster. |
netstat -o |
Adds the owning process ID to each line. |
findstr :3000 |
Keeps only the lines that contain :3000. |
taskkill /PID |
Selects the process to end by its ID. |
taskkill /F |
Forces it to end. Without it, taskkill only asks the process to close, and a Node server often ignores that. |
Good to know#
findstrmatches text, not ports.:3000also matches:30001, and lines where3000is the remote port. Check the local address column before you copy a PID.- Ignore lines in the
TIME_WAITstate with PID0. Those are closed connections that Windows is still cleaning up, and they disappear on their own. - Check what a PID belongs to before you kill it:
tasklist /FI "PID eq 18244"
- If
taskkillsays Access is denied, the process was started as Administrator. Open the terminal as Administrator and run the command again. - In Git Bash, double the slashes, because Git Bash converts arguments that start with
/into file paths:
taskkill //PID 18244 //F