Originally published on DevToolHub.
"Address already in use" tells you a port is taken. It doesn't tell you by what. Finding the actual process bound to a port on Linux is a three-command workflow, not one magic incantation — and two of those three commands have a syntax gotcha that produces wrong or misleading output if you get it backwards.
Step 1: Confirm the port is actually bound, with ss
ss -tlnp is the fastest way to see what's listening. -t restricts output to TCP sockets, -l shows only listening sockets, -n skips reverse-DNS lookups so it returns instantly, and -p shows the owning process — in practice you need sudo to see details for other users' processes.
ss -tlnp | grep :8080
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("node",pid=48213,fd=22))
That already gives you the PID and process name. ss only covers network sockets, though — it won't show a stale listener's other open file handles.
Step 2: Confirm the exact process, with lsof
lsof -i :8080 answers the same question from the file-descriptor side. lsof's -i accepts [46][protocol][@hostname|hostaddr][:service|port], so -i :8080 means any protocol/host on port 8080, while -i tcp:8080 narrows to TCP only.
lsof -i :8080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 48213 deploy 22u IPv4 812933 0t0 TCP *:8080 (LISTEN)
The FD column matters if you're also chasing a "too many open files" error — lsof shows every open file and socket for that PID.
Step 3: Inspect the process before you kill it
ps -p 48213 -o pid,ppid,user,cmd,%cpu,%mem
The gotcha: ps aux and ps -aux are not the same command. Per the ps man page, ps -aux under POSIX rules means "processes with a terminal plus processes owned by a user named x," and it only behaves like ps aux because ps falls back to that when no user x exists. Stick to ps aux for the traditional listing, and ps -p PID -o ... once you have a specific PID.
If you're hunting the heaviest process by resource use instead, ps aux --sort=-%cpu | head sorts descending by CPU — and per the man page, %cpu "will not add up to 100% unless you are lucky," since it's a lifetime ratio, not a live snapshot like top produces.
Killing it safely
kill -15 48213
-15 sends SIGTERM, a clean-shutdown request. Only escalate to kill -9 48213 (SIGKILL) if the process is still alive a few seconds later — SIGKILL skips cleanup and can leave sockets or lock files behind.
Quick Summary:
-
ss -tlnp | grep :PORTfinds the PID fastest, with-navoiding slow DNS lookups -
lsof -i :PORTcross-checks from the file-descriptor side and shows every open file for that PID -
ps -auxmeans "processes owned by userx" under POSIX and only falls back tops aux— typeps auxwithout the dash -
%cpuis a lifetime ratio and won't sum to 100% across processes - Send SIGTERM (
kill -15) before SIGKILL (kill -9)
Full workflow at DevToolHub.
Top comments (0)