Linux and Bash for Developers · Processes and Resources

Address Already in Use

Find which process owns a port, stop it safely, and understand why a restarted server can't bind immediately.

Create a free account to save this page, take notes and track your progress. Sign in

Scenario

You restart a service and it crashes at startup with OSError: [Errno 98] Address already in use. The old process seems gone. Someone runs kill -9 on every Python process on the box.

What you see in production

  • A server fails to start with "Address already in use" (EADDRINUSE).
  • A previous instance, a forgotten dev server, or another service is listening on the port.
  • Restarting the same server quickly sometimes fails and sometimes works.

The naive code

python3 app.py &          # started by hand last week and forgotten
systemctl restart app     # the real service now can't bind port 8080
pkill -9 python           # "fix": kills every Python process on the machine

Reproduce it

Two servers, one port
python3 -m http.server 18431 --bind 127.0.0.1 >/dev/null 2>&1 &
first=$!
sleep 0.5
python3 -m http.server 18431 --bind 127.0.0.1 2>&1 | tail -n 1
kill $first; wait $first 2>/dev/null || true

Output

OSError: [Errno 98] Address already in use

Run this on your computer — see “Get Started” for setup.

Root cause

Only one socket can listen on an address and port unless both opt into sharing. Some other process (often an old instance) already holds it. Separately, a closed server's connections can linger in TIME_WAIT; servers that don't set SO_REUSEADDR may fail to rebind for a short time after a restart.

The fix

Find the owner first, then stop exactly that process, gracefully:

Find and stop the process holding a port
python3 -m http.server 18432 --bind 127.0.0.1 >/dev/null 2>&1 &
sleep 0.5
ss -ltnp 'sport = :18432' | awk 'NR > 1 { print "listening:", $4, $6 }' | sed 's/,fd=[0-9]*//'
pid=$(ss -ltnp 'sport = :18432' | grep -o 'pid=[0-9]*' | head -n 1 | cut -d= -f2)
ps -o pid=,args= -p "$pid" | sed 's/^ *[0-9]* /process: /'
kill -TERM "$pid"
sleep 0.5
ss -ltn 'sport = :18432' | grep -q LISTEN || echo "port 18432 is free"

Output

listening: 127.0.0.1:18432 users:(("python3",pid=3921236))
process: python3 -m http.server 18432 --bind 127.0.0.1
port 18432 is free

Run this on your computer — see “Get Started” for setup.

  • ss -ltnp (or lsof -i :PORT) shows the listening process; -p needs root for other users' processes.
  • Stop it with SIGTERM (or systemctl stop if it's a service), and only use SIGKILL if it won't exit.
  • Run services under a supervisor (systemd, Docker) so there's exactly one managed instance.
  • Servers should set SO_REUSEADDR (most frameworks do) so restarts don't fail on TIME_WAIT.

Trade-offs

  • pkill -9 python may kill unrelated processes and skips cleanup.
  • Changing the port works around the conflict but leaves a rogue process running.
  • SO_REUSEPORT lets several processes share a port for load balancing; don't confuse it with fixing conflicts.

Detect it in production

  • Service logs show EADDRINUSE at startup; alert on crash loops.
  • Inventory listening ports regularly (ss -ltn) and compare against what should be running.
  • In containers, map ports explicitly and check docker ps for duplicates.

Key points

  • Find the owner with ss or lsof before killing anything.
  • Stop processes gracefully, and let a supervisor own the service.
  • Know the difference between a real conflict and TIME_WAIT on restart.

Further reading: ss(8) · socket(7): SO_REUSEADDR

Practice questions

How do you find which process is listening on port 8080?

Answer

ss -ltnp 'sport = :8080' (or lsof -i :8080); root is needed to see other users' processes.

Why might a server fail to bind right after a restart even though the old process exited?

Answer

Old connections can linger in TIME_WAIT; servers that don't set SO_REUSEADDR can't rebind until they expire.

Why avoid pkill -9 to free a port?

Answer

It can kill unrelated processes and gives none of them a chance to clean up; find the owner and stop it with SIGTERM first.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?