EADDRINUSE: Address Already in Use — How to Free the Port
Error: listen EADDRINUSE: address already in use :::3000
Only one process can listen on a given port at a time. This error means something already has port 3000 — usually an earlier copy of your own server that never shut down. The fix is two steps: find the process, then stop it.
Find what's using the port
macOS and Linux:
lsof -i :3000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 48213 alex 23u IPv6 0x8f… 0t0 TCP *:3000 (LISTEN)
The PID column is what you need. On Linux without lsof, ss shows the same:
ss -ltnp | grep :3000
Windows (Command Prompt):
netstat -ano | findstr :3000
The last column is the PID. In PowerShell:
Get-NetTCPConnection -LocalPort 3000 | Select-Object OwningProcess
Stop it
kill 48213 # ask it to exit cleanly
kill -9 48213 # force it, if it ignores the first
Or in one line, on macOS and Linux:
kill $(lsof -ti :3000)
On Windows:
taskkill /PID 48213 /F
Before you kill anything, check the command name. If it isn't yours — a database, another app, a system service — change your app's port instead.
Why it keeps happening
- A dev server still running in another terminal, or a background job you forgot. Close it properly with Ctrl+C rather than closing the window.
- A crashed run left a child process behind. Tools that spawn your server (nodemon, concurrently, npm scripts) can leave an orphaned process if they're killed abruptly.
- Your code calls
listen()twice — for example, the app module starts the server and your test setup starts it again. - A Docker container publishes the port.
docker psshows it in the PORTS column; stop the container or map it elsewhere. - Port 5000 on macOS. Since macOS Monterey, the AirPlay Receiver listens on ports 5000 and 7000. Use another port, or turn off AirPlay Receiver in System Settings → General → AirDrop & Handoff.
Make your server fail clearly and exit cleanly
Read the port from the environment so you can move it without editing code, and turn the crash into a readable message:
const PORT = Number(process.env.PORT) || 3000;
const server = app.listen(PORT, () => console.log(`Listening on ${PORT}`));
server.on("error", (err) => {
if (err.code === "EADDRINUSE") {
console.error(`Port ${PORT} is already in use. Stop the other process or set PORT.`);
process.exit(1);
}
throw err;
});
// Release the port when you press Ctrl+C or the process is told to stop
for (const signal of ["SIGINT", "SIGTERM"]) {
process.on(signal, () => server.close(() => process.exit(0)));
}
The signal handlers matter most under process managers and containers, which send SIGTERM and wait for a clean exit before forcing one.
The same error elsewhere
The message varies, but the cause is the same:
- Python:
OSError: [Errno 98] Address already in use(Linux) or[Errno 48](macOS) - Go:
listen tcp :8080: bind: address already in use - Docker:
Bind for 0.0.0.0:8080 failed: port is already allocated - nginx:
bind() to 0.0.0.0:80 failed (98: Address already in use)
lsof -i :<port> finds the culprit for all of them. And if the server is running but the browser still can't reach it, the problem is somewhere else — for a reverse proxy, start with 502 Bad Gateway.