Port already in use? Find what's holding it and fix it in a minute - DEV Community

DEV Community

Cover image for Port already in use? Find what's holding it and fix it in a minute
VeloxaHost
VeloxaHost

Posted on

Port already in use? Find what's holding it and fix it in a minute

You start your app and it dies straight away:

Error: listen EADDRINUSE: address already in use :::3000
bind() to 0.0.0.0:80 failed (98: Address already in use)
Bind for 0.0.0.0:8080 failed: port is already allocated
Enter fullscreen mode Exit fullscreen mode

Three tools, three wordings, one meaning: something else is already listening on that port. Here's how to find out what in about a minute, and how to fix it without breaking anything else.

Step 1: find who owns the port

Ask the kernel. On any modern Linux server:

sudo ss -ltnp 'sport = :3000'
Enter fullscreen mode Exit fullscreen mode

You'll get a line like:

LISTEN 0 511 *:3000 *:* users:(("node",pid=48213,fd=21))
Enter fullscreen mode Exit fullscreen mode

That's the process name and its PID. Two alternatives if you prefer them:

sudo lsof -i :3000
sudo fuser 3000/tcp
Enter fullscreen mode Exit fullscreen mode

Use sudo. Without it you often can't see processes owned by other users, and the output is empty, which makes it look like nothing is using the port.

Now match what you found to one of the cases below.

Case 1: an old copy of your own app

The most common one. A previous npm start, a nodemon you forgot in another terminal, a screen or tmux session, or a crashed run that left a child process behind.

Stop it gently first, then harder only if you must:

kill 48213          # asks the process to exit cleanly
kill -9 48213       # only if it ignores the first one
Enter fullscreen mode Exit fullscreen mode

If the app is managed by something, stop it there instead, or it will just come back:

pm2 list && pm2 stop myapp
sudo systemctl stop myapp
Enter fullscreen mode Exit fullscreen mode

Case 2: another web server on 80 or 443

You install Nginx and it fails on port 80 because Apache is already there (or the other way round). Some server images ship with one preinstalled.

sudo ss -ltnp 'sport = :80'
sudo systemctl disable --now apache2
sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

Use disable --now, not just stop, or it comes back on the next reboot.

Case 3: a Docker container

If ss shows docker-proxy, a container has published that port. Find it:

docker ps --filter publish=8080
Enter fullscreen mode Exit fullscreen mode

Then stop that container, or docker compose down in its project folder. If two Compose projects both publish 8080:80, change one of them to another host port, like 8081:80.

Case 4: systemd is holding the socket

Some services use socket activation: systemd listens on the port and only starts the service when a connection arrives. Stopping the service isn't enough, because the socket unit still owns the port.

systemctl list-sockets
sudo systemctl stop myapp.socket
Enter fullscreen mode Exit fullscreen mode

On Ubuntu 24.04, SSH works this way (ssh.socket), which is why changing the SSH port needs a socket reload, not just a service restart.

Case 5: it's your own app, restarting too fast

If your server exits and immediately restarts on the same port, a custom server can fail for up to a minute while the old connections finish closing. Most frameworks set the SO_REUSEADDR socket option for you, which avoids this. If you wrote your own socket server, set it yourself before you bind:

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Enter fullscreen mode Exit fullscreen mode

Not the same error: "permission denied"

Error: listen EACCES: permission denied 0.0.0.0:80
Enter fullscreen mode Exit fullscreen mode

That's a different problem. Ports below 1024 need root or a capability. Don't run your app as root to fix it. Run it on a high port like 3000 and put Nginx or Caddy in front on 80 and 443, which is the setup you want in production anyway.

Or just use another port

Sometimes the simplest fix is right: make the port configurable and pick a free one.

PORT=3001 npm start
Enter fullscreen mode Exit fullscreen mode

Then point your reverse proxy at the new port, and you're done.

Checklist

  1. sudo ss -ltnp 'sport = :PORT' to find the process and PID
  2. Old copy of your app? kill PID, or stop it in pm2 or systemd
  3. Apache vs Nginx? systemctl disable --now the one you don't use
  4. docker-proxy? docker ps --filter publish=PORT
  5. Still busy after stopping the service? systemctl list-sockets
  6. EACCES is a different error: use a high port and a reverse proxy
  7. Make the port configurable with PORT=

More fixes

We publish fixes like this every week on the VeloxaHost blog. Running a Node app? See Node.js hosting on VeloxaHost.

Disclosure: we run VeloxaHost, a web hosting and VPS provider. Everything above works on any Linux server.

Top comments (0)