Check what's using a port (Linux / macOS / Windows)
Find which process is listening on a given port number on Linux, macOS, or Windows. Essential for diagnosing port conflicts when a service fails to start.
bash# Replace 8080 with the port number you're investigating
# ── Linux ──��──────────────────────────────────────────────────────────────────
# ss (modern — preferred, no extra install needed)
sudo ss -tulnp | grep ':8080'
# lsof alternative
sudo lsof -i :8080
# ── macOS ─────────────────────────────────────────────────────────────────────
# sudo lsof -i :8080
# sudo lsof -i :8080 -n -P # -n skips DNS lookups, -P shows port numbers
# ── Windows (PowerShell or Command Prompt — run as Administrator) ─────────────
# netstat -ano | findstr :8080
# Then look up the PID shown in the last column:
# tasklist /FI "PID eq 1234"
# To kill the process:
# Stop-Process -Id 1234 -Force
Why these commands
“Address already in use” is one of the most common errors when starting a self-hosted service, and it’s one of the most confusing without knowing how to diagnose it. The service you’re trying to start needs a specific port, but something else is already listening on that port — either a previous instance of the same service that didn’t shut down cleanly, a completely different process that happens to use the same port, or occasionally a service that reserved the port at system startup before your Docker container could claim it.
The socket statistics tools (ss on Linux, lsof on macOS) show you exactly what’s listening on any port and which process owns it — process ID, process name, and the specific socket binding. With that information, you can either stop the conflicting process, move your service to a different port, or identify that you’re dealing with a zombie of your own service that needs to be killed.
The commands differ per OS because socket inspection is implemented at the kernel level, and each OS exposes it differently. Linux’s ss (socket statistics) is the modern replacement for netstat, built-in to every current distribution, and faster because it reads socket state directly from the kernel without a library. macOS uses lsof (list open files — network sockets are files in Unix). Windows uses netstat plus tasklist to correlate PIDs to process names, since Windows networking predates the Unix convention of sockets as files.
When to use this
Run this when:
- A service fails to start with
address already in useorbind: permission denied - You want to confirm a service is actually listening before debugging connectivity
- You need to identify and stop a process occupying a port before starting your own service
Linux
ss — socket statistics (recommended, built-in everywhere)
sudo ss -tulnp | grep ':8080'
Flag breakdown:
-tTCP,-uUDP-llistening sockets only-nshow port numbers (skip DNS/service name lookup)-pshow the process name and PID
Example output:
tcp LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("nginx",pid=1234,fd=6))
To show all listening ports (no filter):
sudo ss -tulnp
lsof — list open files
sudo lsof -i :8080
Find the process name from a PID
ps -p 1234 -o comm=
# or
cat /proc/1234/cmdline | tr '\0' ' '
Kill the process on a port
sudo kill "$(sudo ss -tulnp | grep ':8080' | awk '{print $7}' | grep -oP 'pid=\K[0-9]+')"
# or more safely, get the PID first and verify before killing:
sudo ss -tulnp | grep ':8080'
sudo kill 1234
macOS
sudo lsof -i :8080
Add -n -P to skip slow DNS lookups and show raw port numbers:
sudo lsof -i :8080 -n -P
Example output:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ruby 5678 josh 10u IPv4 0x... 0t0 TCP *:8080 (LISTEN)
Kill the process:
sudo kill 5678
# or force-kill if it doesn't respond:
sudo kill -9 5678
Show all listening ports on macOS
sudo lsof -iTCP -sTCP:LISTEN -n -P
Windows
Open PowerShell or Command Prompt (Administrator):
netstat -ano | findstr :8080
Example output:
TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 4512
The last column is the PID. Look up the process name:
tasklist /FI "PID eq 4512"
Kill the process:
Stop-Process -Id 4512 -Force
Show all listening ports on Windows
netstat -ano | findstr LISTENING
Or in PowerShell for a cleaner view:
Get-NetTCPConnection -State Listen | Sort-Object LocalPort | Select-Object LocalPort, OwningProcess, @{n='Process';e={(Get-Process -Id $_.OwningProcess).Name}}
Notes
- On Linux,
ssreplaces the oldernetstatcommand (net-toolspackage) —ssis faster and always available without installing extra packages - Ports below 1024 require root on Linux/macOS — a service binding to port 80 or 443 must run as root, use
authbind, or sit behind a reverse proxy - On Windows,
netstat -bshows the executable name directly but requires Administrator and is slow —tasklist /FI "PID eq ..."afternetstat -anois faster