Home/Infrastructure/Fixing address already in use: Find and kill the process occupying the port (EADDRINUSE)
Infrastructureaddress already in useEADDRINUSE

Fixing address already in use: Find and kill the process occupying the port (EADDRINUSE)

When bind: address already in use or EADDRINUSE leaves you stuck, this guide walks through finding the occupying process with lsof and netstat, terminating it safely, and stopping TIME_WAIT and duplicate startups with copy-paste commands fo

Fixing address already in use: Find and kill the process occupying the port (EADDRINUSE)
Contents
  1. A red line just appeared in the console — this error means only one thing
  2. Step 1: Diagnose — lookup table by error message pattern
  3. Step 2: Terminate — find the occupying process and kill it safely
  4. Step 3: Prevent recurrence — prescriptions by root cause
  5. Conclusion — 3-step summary and copy-paste checklist
  6. FAQ

Completely fixing address already in use: Find and kill the process occupying the port (EADDRINUSE)

A red line just appeared in the console — this error means only one thing

If you're trying to start a server and the console dumps bind: address already in use or EADDRINUSE, the message is really saying just one thing.

A single port can be occupied by only one process at a time.

In other words: "someone is already holding the port you want (e.g. 8080)." The culprit is one of three:

  1. Yourself — a server you started a moment ago is still alive (hot-reload orphan processes are a classic)
  2. Another process — a completely unrelated app already claimed the same port
  3. A container — Docker has mapped and is holding the host port

This post is structured so you can finish by following diagnose → terminate → prevent recurrence. Copy-paste from top to bottom.

Step 1: Diagnose — lookup table by error message pattern

First, look at the exact message in the console. The wording differs by environment, but the essence is the same.

EnvironmentActual console outputLikely culpritFirst command to run
Node.jsError: listen EADDRINUSE: address already in use :::8080Usually the app itself (duplicate start / nodemon orphan)lsof -i :8080
PythonOSError: [Errno 98] Address already in useleftover process from a uvicorn/flask restartlsof -i :8000
nginxbind() to 0.0.0.0:80 failed (98: Address already in use)another web server / previous nginx instancess -ltnp 'sport = :80'
DockerBind for 0.0.0.0:8080 failed: port is already allocatedanother container holding the host portdocker ps

Once you've found your case in the table, use the first command to identify who is holding the port.

Step 2: Terminate — find the occupying process and kill it safely

All examples below use port 8080. Replace it with your own port before running.

Linux / macOS

Bash
# 1) (PID) check
lsof -i :8080

# 2) — ss lsof
ss -ltnp 'sport = :8080'

# 3) fuser check
fuser 8080/tcp

Once you've identified the PID column in the lsof -i :8080 output, terminate it.

Bash
#
kill -15 <PID>

# 10 quit
kill -9 <PID>

# fuser quit
fuser -k 8080/tcp

Windows (PowerShell / CMD)

POWERSHELL
# PID ( PID)
netstat -ano | findstr :8080

# PID quit
taskkill /PID <PID> /F

kill -15 vs kill -9: order matters

  • kill -15 (SIGTERM): a "clean up and leave" signal. The app closes open files, tears down DB connections, then exits. Always use this first.
  • kill -9 (SIGKILL): kills the process immediately. Blindly using -9 can lose in-flight data or leave lock files and temporary sockets behind, making things worse. Use it only as a last resort when SIGTERM does not work.

Step 3: Prevent recurrence — prescriptions by root cause

Killed it, started again, and the same error came back? Then you need to pull the cause out by the roots.

1) Leftover TIME_WAIT sockets → SO_REUSEADDR

If you stop a server and start it again immediately, the socket you just closed stays in TIME_WAIT for tens of seconds and holds the port, causing EADDRINUSE. Enabling SO_REUSEADDR lets you reuse a port in that state.

Node.js — net/http servers have SO_REUSEADDR on by default, but it's still a good idea to handle the error explicitly and fail fast.

JavaScript
const server = http.createServer(app);
server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
 console.error(' 8080 . quit.');
    process.exit(1);
  }
});
server.listen(8080);

Python

Python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # TIME_WAIT
s.bind(('0.0.0.0', 8000))
s.listen()

2) Hot-reload orphan processes

If nodemon or uvicorn --reload exits abnormally, child workers lose their parent and linger as orphan processes still holding the port. They often survive even after you close the terminal, so hunting them down with lsof from Step 2 is the reliable fix.

3) Duplicate starts from systemd or pm2

If a process manager is set to auto-restart, it will collide with a server you started by hand.

Bash
# pm2 check
pm2 list

# systemd
systemctl status myapp.service

Before a manual test, stop the manager first with pm2 stop <name> or systemctl stop.

4) Docker Compose port mapping conflicts

Bind for 0.0.0.0:8080 failed: port is already allocated means the host port is already taken.

Bash
# 8080
docker ps

If you find a container whose PORTS column shows 0.0.0.0:8080->..., change only the host port in compose to a free value.

YAML
services:
  web:
    ports:
 - "8081:80" # , as-is

Practical tip: Locally, the most common causes are "the previous server never died" and "forgot to bring compose down." If you use containers, make docker compose down a habit at the end of a session. If hot-reload often leaves orphans, register lsof -i :<port> as a shell alias. Diagnosis drops to 30 seconds.

Conclusion — 3-step summary and copy-paste checklist

  1. Diagnose: use the exact error text to tell whether the culprit is the app, another process, or a container
  2. Terminate: find the PID with lsof -i :<port> (or netstat -ano), then kill -15 → kill -9 if that fails
  3. Prevent recurrence: SO_REUSEADDR, clean up orphans, and check process-manager / compose ports
Bash
# (Linux/macOS)
lsof -i :8080 || ss -ltnp 'sport = :8080'

FAQ

Q. Can I just switch to a different port number? A. As a temporary workaround, yes. But changing the port does not make the zombie/orphan process go away — you're still leaking resources. The real fix is to terminate the occupying process.

Q. Rebooting fixed it for me. Is that the right answer? A. A reboot resets every process and TIME_WAIT socket, so of course it clears. But the cause is still there, so it will come back. Use steps 2–3 in this post to remove the root cause.

Q. Bind fails with Permission denied. Is that a port conflict too? A. No. Ports below 1024 (80, 443, etc.) require root privileges. Run with sudo, use a port 1024 or above like 8080, or grant the capability with setcap. That's a different problem from address already in use.

✦ ✦ ✦
Sources and verification

Sources and checks vary by article. Only articles with a recorded check date, scope and sources below were checked, and only within that scope. For other articles, verify against the current docs for your version before applying anything, and email us about errors. Editorial policy · email us

This article has no recorded human check (date and scope) yet.

Published ·

Comments

Be the first to comment.