EADDRINUSE: address already in use — Cause and Fix

Quick answer

Another process is already listening on that port, and the OS allows only one. Almost always it is a previous instance of your own server that did not shut down. Either free the portnpx kill-port 3000, or find the PID and kill it — or start on a different port.

The exact error string

Node.js throws it the moment the server tries to bind the port:

Error: listen EADDRINUSE: address already in use :::3000
    at Server.setupListenHandle [as _listen2] (node:net:1872:16)
    at listenInCluster (node:net:1920:12)
    at Server.listen (node:net:2008:7)
    at Object.<anonymous> (/app/server.js:10:8)
Emitted 'error' event on Server instance at:
    ...
  code: 'EADDRINUSE',
  errno: -48,
  syscall: 'listen',
  address: '::',
  port: 3000

The :::3000 is IPv6 shorthand for “all interfaces, port 3000.” The number at the end is the port already in use.

What it means

A TCP port can be held by only one listening socket at a time. When your server calls listen(3000) and another process already owns port 3000, the bind fails and Node emits an error event with code: 'EADDRINUSE'. The fix is always one of two things: free the port, or use a different one.

Cause 1: A previous instance is still running

By far the most common case. You restarted the app without the old one exiting — a crashed terminal, a detached process, or a debugger session left the original server holding the port. The “new” start collides with the old one.

The classic beginner trap: pressing Ctrl+Z to “stop” a server only suspends it — the process is backgrounded and keeps holding the port. Always use Ctrl+C to terminate it cleanly. A suspended process is a surprisingly frequent source of EADDRINUSE.

Cause 2: Another app uses the same port

Ports like 3000, 5000, and 8080 are popular. A second project, a Docker container, or a system service (macOS uses port 5000 for AirPlay) may already own it.

Cause 3: nodemon or a watcher restarting badly

If the app spawns a child server or does not close its listener on reload, nodemon restarts it while the old listener still holds the port. Each reload then collides until you kill the orphaned process.

Cause 4: Two starts at once — terminals, IDEs, or Docker

Unlike a leftover process, this is two live things competing for the port. It happens when VS Code’s integrated terminal, a background service, or Docker Compose already runs the server — and then you start it again, for example running npm run dev and node server.js at the same time. A very common version is a Docker container already publishing the port:

# Is a container already publishing the port?
docker ps
# CONTAINER ID   IMAGE     ...   PORTS                    NAMES
# a1b2c3d4e5f6   myapp     ...   0.0.0.0:3000->3000/tcp   web

# Stop it to free the port
docker stop web

The fix: free the port

First find which process holds it, then stop that one process.

macOS / Linux:

# Find the process listening on port 3000
lsof -i :3000
# COMMAND   PID  USER   ...  NAME
# node    51234  you    ...  *:3000 (LISTEN)

# Modern alternative to lsof (often faster, Linux)
ss -ltnp | grep :3000

# Stop it by PID
kill 51234        # graceful
kill -9 51234     # force, only if it ignores the first

Reach for kill first. kill -9 (SIGKILL) force-terminates the process without giving it a chance to close connections or clean up, so reserve it for processes that refuse to exit normally.

Windows (Command Prompt / PowerShell):

:: Find the PID listening on port 3000 (last column)
netstat -ano | findstr :3000
::  TCP    0.0.0.0:3000   0.0.0.0:0   LISTENING   51234

:: Stop it by PID
taskkill /PID 51234 /F

Cross-platform one-liner (recommended):

npx kill-port 3000

Or install it globally so it is always on hand: npm install -g kill-port.

The alternative: use a different port

If you do not need that exact port, read it from an environment variable so it is easy to change and so production can override it:

const port = process.env.PORT || 3000;
app.listen(port, "0.0.0.0", function () {
    console.log("Listening on http://localhost:" + port);
});

// Start on another port without touching code:
//   PORT=3001 node server.js        (macOS / Linux)
//   set PORT=3001 && node server.js  (Windows cmd)

Prevent it: shut down cleanly

Release the port when the process exits so the next start does not collide:

const server = app.listen(port);

function shutdown() {
    server.close(function () {
        process.exit(0);
    });
}

process.on("SIGINT", shutdown);    // Ctrl+C
process.on("SIGTERM", shutdown);   // kill / container stop

One related gotcha: if you see EACCES instead of EADDRINUSE on a low port like 80 or 443, the problem is permission, not a conflict — privileged ports need elevated rights or a reverse proxy.

Frequently Asked Questions

What does EADDRINUSE: address already in use mean?

It means your server tried to listen on a port that another process is already using. An operating system lets only one process listen on a given port at a time, so the second bind fails with EADDRINUSE. Almost always the culprit is a previous instance of your own app that did not shut down.

How do I fix EADDRINUSE on port 3000?

Either free the port or use a different one. To free it, find the process holding the port and stop it: on macOS or Linux use lsof -i :3000 then kill the PID; on Windows use netstat -ano | findstr :3000 then taskkill /PID <pid> /F. The cross-platform shortcut is npx kill-port 3000. Alternatively, start your server on another port via an environment variable.

How do I find what is using a port?

On macOS and Linux, run lsof -i :3000 (or ss -ltnp) to list the process and its PID. On Windows, run netstat -ano | findstr :3000 to get the PID, then tasklist | findstr <pid> to see the program name. Once you know the PID you can stop just that process instead of guessing.

What is the difference between EADDRINUSE and EACCES?

EADDRINUSE means the port is already taken by another process. EACCES on a listen call usually means you lack permission to bind that port — typically a privileged port below 1024, which needs elevated rights. If you see EACCES on port 80 or 443, run with the right privileges or use a higher port behind a reverse proxy.

Why does EADDRINUSE keep happening with nodemon?

If your app spawns a child process or does not close its server on reload, nodemon restarts the app while the old listener is still holding the port, so the new one collides. Make sure the process exits cleanly on SIGTERM/SIGINT (call server.close()), and avoid starting two watchers on the same port. A leftover orphaned node process is the usual cause.

Is EADDRINUSE related to ERR_CONNECTION_REFUSED?

They are opposite sides of the same port. EADDRINUSE happens to the server: it cannot start because something already holds the port. ERR_CONNECTION_REFUSED happens to the client: nothing is listening, so its connection is refused. If you kill the old process to fix EADDRINUSE but forget to start the new server, clients then see connection refused.

Server up and returning JSON?

Format and validate the response in your browser — nothing is uploaded to a server.

JSON Validator JSON Formatter All Error References
About the author

Pasindu Ishan is a software developer based in Sri Lanka. He builds privacy-first developer tools at JSON Dev Tools.