Node.js EADDRINUSE: address already in use when restarting server
Your Node server's port is still held by a previous process. Kill it or pick another port.
What causes EADDRINUSE and the quick fix
You stop your Node server with Ctrl+C, but when you start it again seconds later, you get EADDRINUSE: address already in use :::3000. The OS is still holding the port. Your process didn't fully release it yet. The socket enters a TIME_WAIT state, which on Linux can last 60 seconds. Windows and Mac behave similarly.
The absolute fastest fix: pick a different port number. If your app usually runs on 3000, try 3001 or 8080. That gets you back to work in 10 seconds.
But you probably want to keep the same port. Here's how to actually free it up.
Cause #1: The old Node process is still running
Most common scenario: you closed the terminal or hit Ctrl+Z instead of Ctrl+C. The process keeps running in the background. When you restart, the port is taken by that orphaned process.
How to find and kill it
On Linux or Mac, open a new terminal and run:
lsof -i :3000
You'll see output like:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 12345 you 11u IPv4 0x1234567890abcdef 0t0 TCP *:3000 (LISTEN)
The PID (process ID) is the number you need. In this example it's 12345. Kill it:
kill -9 12345
After you run that, try starting your Node server again. It should bind to port 3000 without error.
On Windows, use:
netstat -ano | findstr :3000
You'll see something like:
TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 12345
The last number (12345) is the PID. Kill it:
taskkill /F /PID 12345
Then restart your server.
Why this happens
When you close a terminal tab that was running a Node process, the process may not be terminated — it just loses its parent. On Unix systems, it gets reparented to init (PID 1) and keeps running. The port stays open.
I've seen this happen constantly with developers using VS Code's integrated terminal: they close the terminal panel thinking that stops the process. It doesn't. You have to explicitly send a SIGTERM or kill the process.
Cause #2: TIME_WAIT state after a graceful shutdown
You properly stop your server with Ctrl+C, but restart immediately and get EADDRINUSE. This is the TIME_WAIT state. On Linux, the socket lingers for 60 seconds by default. On Windows, it's typically 240 seconds. The OS is waiting to make sure any delayed packets don't confuse a new connection.
How to fix it
Option 1: Wait 60 seconds. That's the obvious one. Not great when you're iterating fast.
Option 2: Set the SO_REUSEADDR socket option in your code. This tells the OS it's okay to reuse the address even if TIME_WAIT is active. In Node.js with the built-in http module, it's on by default. If you're using raw net or a custom server, do:
const server = net.createServer();
server.listen({ port: 3000, reuseAddr: true });
But honestly, most Node frameworks (Express, Koa, Fastify) already set this. If you're still seeing the error, it's almost certainly Cause #1, not this.
Option 3: Use the wait-on or cross-port-killer npm package. Install it and run it before your server starts:
npx kill-port 3000
That kills whatever's on the port. Then start your server. It's my go-to for development scripts.
Cause #3: Multiple instances of your app started accidentally
You ran node server.js twice, or your process manager (like pm2 or nodemon) started a second instance. This is common when you have a build script that starts the server and also a watcher that starts it again.
How to check
Run the same lsof or netstat command from above. If you see two lines with LISTEN on port 3000, you have two Node processes. Kill both with kill -9 (or taskkill /F) and restart only one.
Preventing it
If you're using nodemon, check your nodemon.json or package.json scripts for duplicate node server.js calls. Common mistake:
"scripts": {
"start": "nodemon server.js & node server.js"
}
That starts two servers. Remove the extra one.
If you're using pm2, run pm2 list to see all processes. If you have a stale instance, run pm2 delete all and start fresh.
Quick reference summary
| Cause | Symptom | Fix |
|---|---|---|
| Orphaned process still running | Error appears after closing terminal or stopping server incorrectly | Find PID with lsof -i :PORT or netstat, then kill -9 PID |
| TIME_WAIT state | Error appears after clean Ctrl+C, if you restart immediately | Wait 60 seconds, or use reuseAddr: true (usually default), or run npx kill-port |
| Accidental duplicate server | Two Node processes listen on the same port | Kill all Node processes on that port, fix your startup scripts |
That's it. Next time you see EADDRINUSE, don't panic. Check if a process is lingering. If not, wait a few seconds or kill the port. You'll be back to coding in under a minute.
Was this solution helpful?