Find the process on a port, list connected clients and read Recv-Q and Send-Q with ss. Plus replacements for netstat.
The app started, but the port does not answer. Or the port is taken and nobody knows by what. Older guides reach for netstat here, yet on a fresh server it is usually not installed, and everything you used it for is covered by ss. Three questions ss answers in the first minutes: who listens on a port, who is connected right now, and whether connections are piling up.
In short.
sudo ss -tulpnlists listening ports with their processes and bind addresses.ss -tnp 'sport = :22'shows who is connected to port 22.ss -sgives a summary.netstatlives in net-tools, which has not been actively developed for years and is usually absent on fresh images;sstakes almost the same flags. If an app listens on127.0.0.1it cannot be reached from outside, the most common reason for "the port is open but nothing answers". On a listening socketSend-Qis the queue size, not sent bytes.
This is where most network debugging on a server starts. It asks the kernel for open sockets and the process holding each. Run it as root or process names stay hidden:
sudo ss -tulpnFlags: -t TCP, -u UDP, -l listening sockets only, -p show the process, -n numbers instead of service and host names. Output from our server (a few lines kept):
Read the Local Address column first. 0.0.0.0:80 means "accepting connections on every address of this server", so nginx is reachable from outside. 127.0.0.53:53 is a loopback address, reachable only from the server itself: it is systemd's local DNS resolver. That is exactly what "the app listens but is unreachable" looks like: the column shows 127.0.0.1 where you need 0.0.0.0 or the server address. Fix the application bind address, not the firewall.
sshd has two owners: sshd itself and systemd (pid 1). That is normal: on Ubuntu 24.04 systemd opens port 22 (the ssh.socket unit) and hands the socket to sshd, so one socket has two holders.
nginx shows 511 in Send-Q, sshd 4096. On an ordinary connection Recv-Q is bytes received but not yet read by the application, and Send-Q is bytes sent but not yet acknowledged. On a listening socket the numbers mean something else:
511 is nginx's default. The practical rule: if Recv-Q on a listening port stays above zero, the application cannot accept connections fast enough and clients wait or get refused. Zero is the healthy value.
To see live connections on one port, add a filter. Quote it so the shell leaves the expression alone:
sudo ss -tnp 'sport = :22'ESTAB means established. On the left our address and port 22, on the right the client and its ephemeral port, then the process serving it. A non-zero Send-Q is not an error here: those are bytes the server already sent (in our case the output of this very command over SSH) that are not acknowledged yet.
The filters you will use most:
ss -tn state established - established connections only;ss -tn '( dport = :443 or sport = :443 )' - everything touching port 443;ss -tn dst 203.0.113.0/24 - connections to a given subnet;ss -tn state time-wait - connections in TIME-WAIT.For the whole picture instead of individual lines, ss -s is enough:
ss -sThe TCP line shows how many connections are established, how many sit in TIME-WAIT and how many are orphaned (sockets the application has already closed but the kernel still holds). Hundreds or even tens of thousands of TIME-WAIT sockets can be normal on a busy public service. It becomes a problem when ports or file descriptors run out, or latency grows.
The -o flag adds connection timers:
ss -tno state establishedon is the retransmission timer, 100ms is the time left until it fires, the last number is how many retransmits have already happened. A growing retransmit count points to packet loss on the path.
The flags are nearly the same, so the habit carries over. Some netstat features moved to other iproute2 commands:
Before (netstat) | Now | What it shows |
|---|---|---|
| | listening ports and processes |
| | all sockets, numeric |
|
| socket summary and protocol counters |
| | routing table |
| | interface statistics |
If you really need netstat it installs separately: sudo apt install net-tools. It is easier to get used to ss: it is already on the system and usually faster when there are many sockets.
ss comes with iproute2 and asks the kernel directly; netstat belongs to net-tools, which has not been actively developed for a long time. ss has more filters and is usually faster with many connections.
Run sudo ss -ltnp 'sport = :8080' with your port. The Process column shows the name and pid. Without sudo the name is hidden if the process belongs to another user.
Most often the app listens on 127.0.0.1 instead of 0.0.0.0. Check the Local Address column. If it says 127.0.0.1, change the bind address in the application settings. If it says 0.0.0.0 and the port is still closed from outside, look at the firewall.
It is the normal state of recently closed connections. A lot of them on a busy server is normal. It matters only when ports run out or latency grows.
sudo ss -tulpn - who listens on which ports and addresses.0.0.0.0 (reachable from outside) from 127.0.0.1 (local only).ss -tnp 'sport = :22' - who is connected; state, dport and dst filters narrow it down.ss -s is the summary, ss -o shows timers.ip route and ip -s link.