Learn how to find which process is using a specific port on Linux, identify its owner safely, and kill it with the right tool. Covers lsof, ss, fuser, and how to prevent address already in use errors for good.
Prerequisites
- A Linux server or VM with sudo access
- Basic familiarity with the terminal
What this solves
When you start a service or app and see Error: listen EADDRINUSE: address already in use :::3000 or bind: Address already in use, it means another process already has that port open. This tutorial shows how to find exactly which process holds a port, confirm it is safe to kill, and stop it cleanly without resorting to a server reboot.
This applies to any TCP or UDP port conflict: web servers fighting over port 80, a stuck Node.js process holding 3000, or a zombie database process blocking 5432. If you are dealing with Postgres specifically refusing new connections rather than a port conflict, see fix PostgreSQL FATAL sorry, too many clients already instead.
Step-by-step configuration
Understand why address already in use happens
Every listening socket binds to an IP address and port combination. The kernel will not let two processes bind to the same port on the same interface at the same time, so if an old process did not shut down properly, or a previous instance is still running, your new process fails to start.
This commonly happens after a crashed process, a container that did not release its port, or a developer running the same app twice in different terminals.
Install lsof and net-tools if missing
lsof and ss are the two main tools you need. ss ships by default on nearly every modern distro via iproute2, but lsof sometimes needs installing.
sudo apt update
sudo apt install -y lsofsudo dnf install -y lsofFind the process using lsof
The -i flag filters by network connection. Replace 3000 with whatever port is blocked.
sudo lsof -i :3000Typical output looks like this:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 18234 deploy 22u IPv4 184028 0t0 TCP *:3000 (LISTEN)The second column is the PID you will need to kill the process. The USER column tells you which account owns it.
Find the process using ss
ss is faster than lsof on busy systems and is the modern replacement for netstat. Use it when you need a quick overview or when lsof is not installed.
sudo ss -ltnp | grep ':3000'Flags explained: -l shows listening sockets only, -t filters to TCP, -n shows numeric ports instead of resolving service names, -p shows the owning process.
For UDP services such as DNS resolvers or syslog listeners, swap -t for -u.
sudo ss -lunp | grep ':53'Identify the process owner and PID safely
Before killing anything, confirm what the process actually is. Killing the wrong PID can take down an unrelated service, a database, or even an SSH session if port numbers happen to collide.
ps -fp 18234This shows the full command line, parent process, and the user that launched it. If the owner is a system account like postgres or www-data, stopping it with kill directly can leave the service in an inconsistent state. In that case prefer the service's own stop command, for example sudo systemctl stop postgresql, over killing the PID manually.
sudo to inspect or kill it. Never blindly sudo-kill PIDs you have not identified with ps first.Kill the process with kill
Once you have confirmed the PID is safe to terminate, send a graceful termination signal first.
kill -15 18234-15 is SIGTERM, which asks the process to shut down cleanly, closing file handles and finishing in-flight requests. Wait a few seconds and check it is gone.
ps -p 18234If the process ignores SIGTERM and is still running, escalate to SIGKILL, which forces an immediate stop with no cleanup.
kill -9 18234Kill by name with pkill
When multiple processes share a name, for example several stale node workers, killing by PID one at a time is slow. pkill matches by process name or command line pattern.
pkill -15 -f 'node server.js'The -f flag matches against the full command line rather than just the process name, which avoids accidentally killing unrelated processes that happen to be named node.
Always do a dry run first with pgrep to see what would be matched before you kill anything.
pgrep -fa 'node server.js'Kill by port directly with fuser
fuser lets you kill whatever is bound to a port without looking up the PID manually. This is the fastest one-liner for a quick fix in development.
sudo fuser -k 3000/tcpThis sends SIGKILL by default to every process using that port. For a graceful shutdown, send SIGTERM explicitly instead.
sudo fuser -k -TERM 3000/tcpfuser -k kills every process attached to that port, including ones you may not have intended to stop. Run sudo fuser -v 3000/tcp first to see what is actually listening before killing.Prevent conflicts with SO_REUSEADDR
A common cause of repeated address already in use errors is a socket stuck in TIME_WAIT after a restart. Most frameworks and languages let you enable SO_REUSEADDR so the OS allows immediate rebinding to a port in that state.
In Node.js with the built-in net or http module, this is handled automatically on most Linux distributions. For custom C or Python socket servers, set it explicitly before binding.
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 8080))
sock.listen(5)This does not bypass a genuinely active listener. It only allows rebinding to a socket that is winding down in TIME_WAIT, which is the state you see most often right after a restart.
Prevent conflicts with systemd socket activation
For services managed by systemd, socket activation lets systemd own the listening socket and hand it to your application on demand. This avoids race conditions where two instances of your app try to bind the same port during a restart.
[Unit]
Description=Socket for myapp
[Socket]
ListenStream=8080
[Install]
WantedBy=sockets.target[Unit]
Description=My application
Requires=myapp.socket
[Service]
User=myapp
ExecStart=/usr/local/bin/myapp
Restart=on-failure
[Install]
WantedBy=multi-user.targetEnable the socket unit, not the service directly. systemd will start the service automatically the first time a connection arrives on the socket.
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.socketIf you run multiple backend instances behind a reverse proxy, you may also want to look at configuring systemd user services for application startup to manage per-user app instances cleanly.
Check listening ports on startup
Add a quick habit of checking what is already listening before you start a new service, especially on shared development boxes.
sudo ss -ltnpFor a persistent audit trail, you can also script a check that runs at boot and logs all listening ports to a file for later review.
sudo ss -ltnp > /var/log/listening-ports-$(date +%Y%m%d).logIf you want this automated on a schedule rather than a one-off check, configuring cron jobs and system task scheduling covers how to run checks like this reliably.
Verify your setup
After killing the process, confirm the port is actually free before starting your application again.
sudo ss -ltnp | grep ':3000'
sudo lsof -i :3000Both commands should return no output if the port is clear. Then start your service and verify it binds successfully.
sudo systemctl status myapp
curl -I http://127.0.0.1:3000Common issues
| Symptom | Cause | Fix |
|---|---|---|
| lsof shows nothing but port still fails to bind | Process is bound to IPv6 only, lsof filter missing protocol | Run sudo lsof -i6:3000 and sudo lsof -i4:3000 separately |
| Permission denied when running lsof or ss | Process owned by another user or system account | Prefix the command with sudo to see root-owned sockets |
| kill -9 does not free the port immediately | Socket is in TIME_WAIT, not actually still bound by a live process | Wait 30-60 seconds, or enable SO_REUSEADDR in the app code |
| Port reopens right after killing the process | A supervisor like systemd or PM2 auto-restarts it | Stop the service unit first: sudo systemctl stop myapp |
| fuser reports No process specified | Wrong protocol suffix used | Confirm TCP vs UDP, try sudo fuser -v 3000/tcp |
| Multiple PIDs returned for the same port | Forked worker processes sharing a listening socket | Kill the parent PID shown in ps -f --ppid, not individual workers |
Next steps
- Fix PostgreSQL FATAL sorry, too many clients already
- Configure Linux system services with systemctl and service management
- Configure systemd user services for application startup
- Fix systemd service keeps restarting in a loop
- Configure Linux firewall rules with fail2ban