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.

Best practices
Illustration of an event loop and asynchronous tasks

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

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting