Short answer: to find what's using a port on Linux, run ss -tlnp | grep <port> — it shows the process name and PID holding that port. If it shows nothing, try lsof -i :<port> or fuser <port>/tcp as a cross-check, then free the port with kill <PID> and confirm it is gone before restarting your program. I tested all three tools on November 2, 2026, on a Linux virtual machine, against a real listening process — and all three independently pointed at the same PID.
The scenario is familiar: you start a server or dev tool and it dies with Address already in use. Something else grabbed the port first — an old copy of the program, or a service that starts at boot. The tools below take about ten seconds.
The test: one mystery listener, three tools
To make this a real test rather than a description, I started a small web server on port 8765 with Python's built-in HTTP server:
python3 -m http.server 8765
Then, without looking at which process I had just started, I interrogated port 8765 with each tool. The test machine is a Linux virtual machine running ss from iproute2 6.1.0 and lsof 4.95.0. Here is what each tool reported:
| Tool | Command | What it reported |
|---|---|---|
| ss | ss -tlnp \| grep 8765 |
python3, PID 16536, listening on 0.0.0.0:8765 |
| lsof | lsof -i :8765 |
python3, PID 16536, TCP *:8765 (LISTEN) |
| fuser | fuser 8765/tcp |
PID 16536 |
Three tools, one answer: PID 16536. That agreement is the point — if two tools disagree, trust the one that names a process you can verify with ps, and re-check with sudo (see below). I also confirmed the conflict itself: starting a second server on the same port failed exactly as a real user would see it, with OSError: [Errno 98] Address already in use.
Method 1: ss — the fastest check
ss is the modern replacement for netstat and is preinstalled on virtually every current Linux distribution. The flags each do one job:
-t— TCP sockets only (use-ufor UDP, covered below)-l— listening sockets only, which is what "using a port" means here-n— show port numbers instead of trying to resolve them to service names-p— show the process using the socket
Run it, filtered to your port:
ss -tlnp | grep 8765
Real output from my test:
LISTEN 0 0 0.0.0.0:8765 0.0.0.0:* users:(("python3",pid=16536,fd=3))
Reading it: the process python3 with PID 16536 is listening on all interfaces (0.0.0.0) at port 8765. If you see 127.0.0.1:8765 instead, the program is only reachable from the same machine — useful to know if you expected it to be public.
One common gotcha: if the Process column is empty or missing, the listener belongs to another user (often root or a system service) and ss cannot show it to you. Re-run with sudo ss -tlnp | grep <port> and the process will appear.
Method 2: lsof — when you want the most detail
lsof lists open files, and on Linux a network socket counts as a file. Its port syntax reads naturally:
lsof -i :8765
Real output from my test:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python3 16536 root 3u IPv4 542333 0t0 TCP *:8765 (LISTEN)
This tells you more than ss at a glance: the command name, the PID, the user running it (root here, because that is how the test server was launched), and the connection state. lsof -i -P -n lists every network connection without resolving names, handy when you do not yet know which port to blame. lsof may not be preinstalled on minimal systems — on Debian/Ubuntu, sudo apt install lsof fixes that.
Method 3: fuser — the one-line answer
If you just want the PID and nothing else, fuser is the shortest route:
fuser 8765/tcp
Real output from my test:
8765/tcp: 16536
That is the whole answer: PID 16536. For UDP, swap the suffix: fuser 9876/udp. And fuser can also do the killing for you — fuser -k 8765/tcp sends a signal to every process using that port — but I recommend the explicit kill below instead, because it forces you to look at the process first. Killing blindly is how you take down a database you meant to keep.
Freeing the port, and proving it is free
Once you know the PID, check what it actually is before killing it:
ps -p 16536 -o pid,comm,args
If it is the stale copy of your program, a leftover dev server, or anything you recognise as safe to stop, end it politely first — a normal kill lets the program shut down cleanly:
kill 16536
Only if the process ignores that (check again after a few seconds) should you escalate to kill -9 16536, which cannot be ignored but also gives the program no chance to save state or release files cleanly.
Then — this is the step people skip — verify the port is actually free before restarting your program:
ss -tlnp | grep 8765
In my test, after the kill, that command returned nothing: port 8765 was free. I then started the server again on the same port and it came straight up (as a new process, PID 16556) — proof the conflict is resolved, not just hidden. If your program still fails with "Address already in use" after a kill, the usual cause is a parent process or a service manager restarting it — check systemctl status for a service of the same name, or look for a parent PID with ps -o ppid= -p <PID> before the kill.
What about UDP ports?
The same three tools work for UDP; only the flag changes. I verified this separately by binding a UDP socket on port 9876 and checking it:
ss -ulnp | grep 9876
lsof -i udp:9876
Both named the same process (PID 16686), and after killing it, ss confirmed UDP port 9876 was free. One difference worth knowing: UDP has no "listening" state the way TCP does, so ss shows UDP sockets as UNCONN (unconnected) rather than LISTEN — that is normal and does not mean the port is free.
FAQ
Why does ss show the port but no process name?
The listener belongs to a different user than the one running ss. Re-run with sudo and the process column will fill in.
Can two programs share one port?
Not on the same address and protocol, in normal use — that is exactly why the second server in my test failed with "Address already in use". A program can bind the same port on different addresses (for example, one on 127.0.0.1 and one on a public IP), and there is an advanced socket option for sharing, but for everyday troubleshooting, one port means one listener.
I killed the PID but the port is still taken. Now what?
Something restarted it. Check whether a service manager owns it (systemctl status <name>), whether a parent process respawned it, or whether you killed one worker of a multi-process program and another took over. Find the parent or the service, stop that, and the port stays free.
Which tool should I learn first?
ss. It is preinstalled everywhere, it is the fastest, and its output already contains the PID you need. Keep lsof as the backup for when you want the user and file details, and fuser for the shortest possible answer.
Conclusion
A "port already in use" error looks cryptic, but it is a ten-second diagnosis: ss -tlnp | grep <port> names the process, ps confirms what it is, kill frees the port, and a second ss run proves it. In my test all three tools — ss, lsof, and fuser — agreed on the same PID, the kill freed the port, and the server restarted cleanly on it. Learn the ss one-liner and this whole class of problem stops being a mystery.
How this article was made
I tested this on November 2, 2026, on a Linux virtual machine (ss from iproute2 6.1.0, lsof 4.95.0, Python 3.12.3): I started a real HTTP server on TCP port 8765 and a UDP socket on port 9876, checked both with ss, lsof, and fuser, confirmed a second server on the same port fails with "Address already in use", killed the listeners, and verified both ports were free and reusable. Every command output quoted above is real output from that test. Flag meanings were cross-checked against the official manual pages for ss and lsof. This article was written with AI assistance (Tiny, TechVerge's AI assistant) and every test result reported here was run by hand on the test machine.
Sources: ss manual page, lsof manual page.
