Fix EADDRINUSE in a Node.js server
Identify the listener that owns the address, stop or reconfigure the right service, and distinguish application bind failures from container port conflicts.
EADDRINUSE means a server could not bind because the requested address is already in use. Identify the owner before stopping anything. It may be another service, an older application instance, or a second server created by your own code.
Find the listener
On macOS or a Linux system with lsof:
lsof -nP -iTCP:3000 -sTCP:LISTEN
On Windows PowerShell:
Get-NetTCPConnection -LocalPort 3000 -State Listen |
Select-Object LocalAddress, LocalPort, OwningProcess
Inspect the reported process and its command. Windows netstat -ano is another option; a text filter for :3000 can also match unrelated rows, so inspect the local address and listening state rather than trusting the filter alone.
Stop or reconfigure the intended service
If a service manager owns the process, stop it through that manager so it is not immediately restarted. For a verified Unix development process, a normal termination signal gives it a chance to clean up:
kill -TERM 12345
Replace the example PID with the one you actually identified. Force termination such as kill -KILL or Windows taskkill /PID 12345 /F is a last resort when deliberate normal shutdown fails; it prevents normal cleanup. Avoid broad name-based killing that could stop other Node applications.
Alternatively, select another configured port and update the client or proxy that connects to it. In development tests, port 0 lets the operating system allocate an available port; read it from server.address() after the server starts.
Handle startup failure
This standalone CommonJS example reports the collision without forcing output to be discarded:
const http = require('node:http');
const server = http.createServer((req, res) => res.end('OK'));
server.on('error', (error) => {
if (error.code === 'EADDRINUSE') {
console.error('Port 3000 is already in use; inspect the existing listener');
} else {
console.error(error);
}
process.exitCode = 1;
});
server.listen(3000, '127.0.0.1');
In a larger application, close any resources opened before startup failed. Setting an exit code alone does not close a database pool or another server.
Check repeated starts and address scope
A supervisor, development reloader, second terminal, or duplicate application initialization can start another listener. Check both IPv4 and IPv6 listeners: wildcard binds can conflict with more specific addresses. TIME_WAIT is not a sufficient diagnosis by itself; Node's TCP servers use address-reuse behavior, and waiting blindly may leave a duplicate live service untouched.
Creating two server objects on one endpoint can produce EADDRINUSE. Calling listen() again on the same already-listening server is a separate API misuse and may produce ERR_SERVER_ALREADY_LISTEN.
FAQ
Why does the port become busy again after I stop the process? Check whether a supervisor restarts it, whether another instance remains, and whether you identified the correct listener.
Can I retry on another port? Yes, with a bounded retry policy, but tell clients which port was selected. Production routing usually expects a configured endpoint, so silent fallback can hide a failed deployment.
What about Docker? A host published-port collision is usually reported by Docker while creating or starting the container. An application's own EADDRINUSE concerns binding inside its network namespace, unless it shares the host's network namespace. Diagnose the error at the layer that emitted it.
After repair, confirm the expected process owns the listener and call a representative endpoint. A listening socket alone does not prove the right application is healthy.
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan