Skip to content
Commitpedia
Log in Join & edit

Fix: Address already in use (free a busy port)

Your server cannot start because another process already listens on its port. This script shows which process holds the port and stops it, politely first.

Not checked by a trusted editor yet Last edited Outdated?

Edit history of Fix: Address already in use (free a busy port): 1 recorded edit
Edit history · 1 edit
Type
Script
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Language
bash
Licence
CC0-1.0

What this changes

Stops the processes listening on PORT: it sends SIGTERM after you answer y (or at once with --force), then SIGKILL to any still running after 5 seconds. Unsaved work in those programs is lost; no files are changed.

How to undo it

A stopped process cannot be resumed; start the program again yourself, for example your dev server. Read the process list it prints before you answer y.

Only one process can listen on a given TCP port and address at a time. If you start a dev server while an old copy is still running, perhaps in another terminal tab or left behind by a crash, you get an error like one of these:

OSError: [Errno 98] Address already in use          # Python on Linux
OSError: [Errno 48] Address already in use          # Python on macOS
Error: listen EADDRINUSE: address already in use :::3000   # Node.js

The fix is to find the process holding the port, decide whether it is safe to stop, and stop it. Or simply run your server on a different port.

Doing it by hand

lsof -nP -iTCP:3000 -sTCP:LISTEN     # who is listening on 3000?
ps -o pid,user,command -p 12345      # more detail about that PID
kill 12345                           # ask it to stop (SIGTERM)
kill -9 12345                        # force it (SIGKILL) only if it ignores SIGTERM

On Linux systems without lsof, use ss -ltnp 'sport = :3000' instead. Seeing processes owned by other users may require sudo.

The script

#!/usr/bin/env bash
set -euo pipefail

# Usage: freeport.sh PORT [--force]
PORT=${1:?usage: freeport.sh PORT [--force]}
FORCE=${2:-}

[[ "$PORT" =~ ^[0-9]+$ ]] || { echo "port must be a number" >&2; exit 2; }

PIDS=$(lsof -nP -t -iTCP:"$PORT" -sTCP:LISTEN 2>/dev/null || true)
if [[ -z "$PIDS" ]]; then
  echo "Nothing is listening on port $PORT."
  exit 0
fi

echo "Listening on port $PORT:"
for pid in $PIDS; do
  ps -o pid=,user=,command= -p "$pid"
done

if [[ "$FORCE" != "--force" ]]; then
  read -r -p "Stop these processes? [y/N] " answer
  [[ "$answer" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 1; }
fi

for pid in $PIDS; do
  kill -TERM "$pid" 2>/dev/null || true
done

for _ in 1 2 3 4 5; do
  sleep 1
  STILL=$(lsof -nP -t -iTCP:"$PORT" -sTCP:LISTEN 2>/dev/null || true)
  [[ -z "$STILL" ]] && { echo "Port $PORT is free."; exit 0; }
done

echo "Still running after SIGTERM, sending SIGKILL: $STILL"
for pid in $STILL; do
  kill -KILL "$pid" 2>/dev/null || true
done

Usage

chmod +x freeport.sh
./freeport.sh 3000            # shows the process and asks before stopping it
./freeport.sh 8000 --force    # no prompt, for use in other scripts

How it works

  • lsof -t prints only process IDs. -iTCP:PORT -sTCP:LISTEN limits the list to processes listening on that port, so client connections to the port are not touched. -nP skips slow DNS and port-name lookups.
  • ps -o pid=,user=,command= prints who owns each process and the full command line, so you can see what you are about to stop.
  • It sends SIGTERM first. That is a polite request that lets the program close files and connections cleanly.
  • It waits up to five seconds, checking each second. Only if something is still listening does it send SIGKILL, which cannot be caught or ignored but gives the program no chance to clean up.
  • If nothing is listening, it says so and exits with status 0, so it is safe to call before starting a server.

Understanding processes

Every running program has a process ID (PID). ps aux lists all processes, and top (or htop if installed) shows a live view sorted by CPU use. kill does not necessarily kill: it sends a signal, and SIGTERM (the default) asks nicely. kill -l lists all signals.

If the process belongs to another user or to the system, kill fails with “Operation not permitted”. Think twice before using sudo there: a system service on port 80 or 5432 is usually better managed with its service manager, for example systemctl stop on Linux or brew services stop for Homebrew services.

Avoiding it next time

  • Stop dev servers with Ctrl+C rather than closing the terminal tab.
  • Make your app’s port configurable, for example PORT=3001 npm start, so you can run two copies side by side.
  • If the error comes from Docker (port is already allocated), check docker ps for a container that already publishes the port.

See also

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Commitpedia +4,084 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?