The EADDRINUSE error means the port you are trying to use is already occupied by another process. This guide covers the fastest way to kill the blocking process on every OS, plus how to prevent this error permanently.
The Error Message
What you see in the terminal:
Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (net.js:1318:16)
at listenInCluster (net.js:1366:12)
at Server.listen (net.js:1452:7)
at Function.listen (/app/node_modules/express/lib/application.js:618:24)
at Object.<anonymous> (/app/server.js:10:5)Port 3000 in the error can be any port — 4000, 8080, 5173, or whatever your app uses.
Fix on Mac / Linux
Three commands — from fastest to most explicit:
Option 1: One-liner (fastest)
Kill port 3000 in one command:
lsof -ti:3000 | xargs kill -9 # For port 8080: lsof -ti:8080 | xargs kill -9
lsof -ti:3000 outputs just the PID, which is piped directly to kill -9.
Option 2: Find PID first, then kill
Two-step approach — see what is running first:
# Step 1: Find the process lsof -i :3000 # Output: # COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME # node 12345 john 23u IPv6 ... 3000 (LISTEN) # Step 2: Kill it using the PID kill -9 12345
Option 3: fuser (Linux only)
Linux alternative using fuser:
# Kill all processes on TCP port 3000 fuser -k 3000/tcp # Verbose output (shows PIDs before killing) fuser -v -k 3000/tcp
Fix on Windows
Find and kill with netstat + taskkill:
# Step 1: Find which process uses port 3000 netstat -ano | findstr :3000 # Output: # TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 12345 # Step 2: Kill the process by PID (12345 in this example) taskkill /PID 12345 /F # Or kill by process name: taskkill /IM node.exe /F
Run Command Prompt or PowerShell as Administrator if you get permission errors.
Add npx kill-port to package.json Scripts
The kill-port package works on all platforms (Mac, Linux, Windows) and can be chained into your start script so the port is always freed before your server launches.
package.json — auto-kill port on start:
{
"scripts": {
"dev": "npx kill-port 3000 && node server.js",
"start": "npx kill-port 3000 && node server.js",
"kill": "npx kill-port 3000"
}
}
# Now: npm run dev will always free port 3000 first
# Or kill manually: npm run killAutomatically Use Next Free Port
Instead of hardcoding a port, use the portfinder package to automatically find and bind to the next available port.
Auto-select next free port:
// npm install portfinder
const portfinder = require('portfinder');
const express = require('express');
const app = express();
portfinder.basePort = 3000; // start searching from 3000
portfinder.getPortPromise()
.then((port) => {
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});
})
.catch((err) => {
console.error('Could not find a free port:', err);
});Prevent It: Use process.on('SIGTERM') for Graceful Shutdown
The most permanent fix is ensuring your server always releases the port when it exits. This prevents zombie processes from accumulating.
Graceful shutdown — always release the port:
const server = app.listen(3000, () => {
console.log('Server running on port 3000');
});
function shutdown(signal) {
console.log(`Received ${signal}, shutting down gracefully...`);
server.close(() => {
console.log('Port released. Process exiting.');
process.exit(0);
});
// Force exit if close takes too long
setTimeout(() => process.exit(1), 5000);
}
process.on('SIGTERM', () => shutdown('SIGTERM')); // Docker stop, Heroku
process.on('SIGINT', () => shutdown('SIGINT')); // Ctrl+CWhy Does This Happen?
- Server crashed mid-run — unhandled exception exits the process without releasing the port
- Ctrl+C timing — the port enters TCP TIME_WAIT state briefly after a fast kill
- Multiple dev servers — running
npm run devtwice without stopping the first one - Hot-reloader re-bind race — nodemon or ts-node-dev restarting before the old socket fully closes
- Docker containers — a stopped container still holding the port binding on the host
Debug your API requests with our HAR to cURL tool →
Convert browser HAR exports to cURL commands you can run from any terminal.
Frequently Asked Questions
What causes EADDRINUSE in Node.js?
Another process is already listening on that port. Common causes include a crashed server that did not release the port, or running two instances of your dev server simultaneously.
How do I kill port 3000 on Mac?
Run lsof -ti:3000 | xargs kill -9 in your terminal. This works for any port — replace 3000 with your port number.
How do I kill a port on Windows?
Run netstat -ano | findstr :3000 to get the PID, then taskkill /PID <pid> /F. Or use npx kill-port 3000.
How can I automatically find the next available port?
Use the portfinder package. Call portfinder.getPortPromise() to get the next free port from your base port.
Why does the port stay in use after stopping my server?
Without a graceful shutdown handler, the OS may keep the port in TIME_WAIT state. Implement process.on('SIGINT') to call server.close() before exiting.