cenko.tech

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#

  • findstr matches text, not ports. :3000 also matches :30001, and lines where 3000 is the remote port. Check the local address column before you copy a PID.
  • Ignore lines in the TIME_WAIT state with PID 0. 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 taskkill says 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

cd ~/blog