Guides

netstat command: netstat -tulpn, the ss equivalents and Windows netstat -ano

The netstat command shows listening ports and connections: netstat -tulpn and its ss equivalents, counting states, Windows netstat -ano and common errors.

Published ~9 min read
On this page

Short answer: sudo netstat -tulpn lists every TCP and UDP port a program listens on, with the PID and name of that program. On current Linux distributions netstat is often not installed, because it belongs to the old net-tools package; sudo ss -tulpn gives the same answer with the same letters and ships with every mainstream distribution. On Windows, netstat -ano lists every connection and listening port with the owning process ID in the last column.

Linux
sudo netstat -tulpn     # net-tools
sudo ss -tulpn          # iproute2: the same question, preinstalled
Windows cmd · PowerShell
netstat -ano

The ss commands below were run on Debian 12 with iproute2 6.1. That server has no netstat at all (command -v netstat prints nothing), so the netstat flags follow the net-tools netstat(8) man page, and the Windows ones Microsoft’s netstat reference.

netstat to ss: the translation table

The netstat man page itself says the program is mostly obsolete and names the replacements: ss for sockets, ip route for netstat -r, ip -s link for netstat -i and ip maddr for netstat -g. Most socket flags carry over letter for letter:

Tasknetstat (net-tools)Replacement (iproute2)
Listening TCP and UDP ports, with processnetstat -tulpnss -tulpn
Listening TCP ports onlynetstat -tlnpss -tlnp
Every TCP socket, any statenetstat -tanss -tan
Connections, without listening socketsnetstat -tnss -tn
Timers (keepalive, retransmit)netstat -tnoss -tno
Owner and inode of each socketnetstat -tness -tne
Unix domain socketsnetstat -xss -x
Summary countsnetstat -sss -s, or nstat -az for every counter
Routing tablenetstat -rnip route
Interface countersnetstat -iip -s link
Multicast groupsnetstat -gip maddr
Refresh every secondnetstat -tancwatch -n 1 ss -tan

One difference catches people out: netstat -s prints hundreds of protocol counters, ss -s only a short summary of socket counts. For the counters, nstat -az (also in iproute2) is the match; without -a it shows only what changed since its last run.

netstat -tulpn, letter by letter

  • -t TCP sockets, -u UDP sockets. Leave both out and netstat shows every family, Unix sockets included, which is a lot of noise.
  • -l listening sockets only: the services waiting for connections, not the connections themselves. -a shows both.
  • -p the PID and program name. It needs root to name processes of other users; without sudo those rows show -.
  • -n numbers instead of names: 0.0.0.0:22 rather than 0.0.0.0:ssh, and no slow reverse DNS lookups for remote addresses.
Example output · sudo netstat -tulpn (addresses and PIDs are examples)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1021/sshd
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1340/nginx: master
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      1188/mariadbd
tcp6       0      0 :::22                   :::*                    LISTEN      1021/sshd
tcp6       0      0 :::80                   :::*                    LISTEN      1340/nginx: master
udp        0      0 127.0.0.53:53           0.0.0.0:*                           587/systemd-resolve

The column to read is Local Address. 0.0.0.0 and ::: mean every IPv4 or IPv6 address, so SSH and nginx above are reachable from the network unless a firewall stops them; 127.0.0.1:3306 means MariaDB accepts connections from the server itself only. UDP has no listening state, so its State column stays empty. The same listing from ss puts the process in a users:(("sshd",pid=1021,fd=3)) column instead; how to read it, and how to test from outside whether a port is really open, is in checking open ports on Linux. Which service normally sits on which number is in the list of common ports.

Is netstat deprecated? Installing it anyway

Yes, in practice. net-tools still builds and works, but its last release, 2.10, came out in 2021, and Debian, Ubuntu and Rocky images no longer install it by default. ss comes with iproute2, which every current distribution ships, and it asks the kernel for socket data directly instead of parsing the text files under /proc/net, which makes it noticeably faster on a server with tens of thousands of connections. If you prefer netstat, one package brings it back:

Debian · Ubuntu
sudo apt install -y net-tools
Rocky · AlmaLinux
sudo dnf install -y net-tools

The same package also restores ifconfig, route and arp; the details, and why ifconfig can still be “not found” afterwards, are in ifconfig: command not found.

Find what listens on a port

Linux
sudo ss -ltnp 'sport = :443'            # ss filters by port itself
sudo netstat -tulpn | grep ':443 '      # netstat: note the space after 443

Grep for :443 with a trailing space, or :443\b, because a bare :443 also matches ports 4430 and 44300. The ss filter has no such trap. Once you have the PID, systemctl status PID names the service it belongs to, so you know what to stop or reconfigure. If a program refuses to start because its port is taken, the next steps are in Address already in use.

Count connections per state

On a busy server the question is often not “what listens” but “how many connections, in which state”. Both tools print the state in a column, so a short pipeline counts them:

Linux
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
netstat -tan | awk 'NR>2 {print $6}' | sort | uniq -c | sort -rn
Example output · ss pipeline
    212 ESTAB
     96 TIME-WAIT
     11 LISTEN
      4 SYN-RECV
      2 CLOSE-WAIT

The ss line skips one header row, the netstat line two, because netstat prints a title above its column names. ss can also filter by state on its own, and then it leaves the State column out of the output. On iproute2 6.1 that makes the remote address the fourth field, which is what the per-address count below relies on:

Linux · ss
ss -s                                             # quick totals
ss -Htn state established | wc -l                 # established connections (-H: no header)
ss -Htn state established '( sport = :443 )' | wc -l   # ...to your HTTPS port
ss -Htn state established | awk '{print $4}' | sed 's/:[0-9]*$//' |
  sort | uniq -c | sort -rn | head                # connections per remote address

What the states mean

ssnetstatMeaningWhen to worry
LISTENLISTENA service waiting for connectionsOnly if it listens on an address it should not
ESTABESTABLISHEDAn open connectionA sudden jump from one address can be a flood or a broken client
TIME-WAITTIME_WAITClosed by this side, kept briefly so late packets are not mistaken for a new connection (60 seconds on Linux)Rarely: thousands are normal behind a busy proxy
CLOSE-WAITCLOSE_WAITThe other side closed; this program has not closed its socket yetWhen the count only grows: the application leaks sockets
SYN-RECVSYN_RECVA handshake that has not completedHundreds at once suggest a SYN flood or a full backlog
SYN-SENTSYN_SENTThis server is trying to connect outIf they pile up, the remote end or a firewall drops the packets
FIN-WAIT-1, FIN-WAIT-2, LAST-ACKFIN_WAIT1, FIN_WAIT2, LAST_ACKConnections in the middle of closingAlmost never

CLOSE-WAIT is the one that points at a bug. The remote side is done and the kernel is waiting for your program to call close(), which never happens. Each of those sockets holds a file descriptor, and if the count keeps growing, the process ends up with too many open files. TIME-WAIT, by contrast, is TCP working as designed, and it is also why a restarted service can briefly fail to bind its port; the TIME_WAIT section of the bind error guide covers that case.

netstat -rn and netstat -i: routes and interfaces

netstat also prints the routing table and per-interface counters, two jobs that moved to the ip command. The same default route in both formats, with example addresses:

Example output · netstat -rn and ip route
$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         203.0.113.1     0.0.0.0         UG        0 0          0 eth0
203.0.113.0     0.0.0.0         255.255.255.0   U         0 0          0 eth0

$ ip route
default via 203.0.113.1 dev eth0 proto static
203.0.113.0/24 dev eth0 proto kernel scope link src 203.0.113.10

0.0.0.0 with flag G (gateway) is the default route, written default via by ip; U means the route is up. A server with no default route can reach its own subnet and nothing else. For interface counters, ip -s link replaces netstat -i: an errors count that keeps climbing between two runs points at the link or the driver.

netstat on Windows: netstat -ano

Windows cmd
netstat -ano                           # all connections and ports, numeric, with PID
netstat -ano | findstr LISTENING       # listening ports only
netstat -ano | findstr :443            # one port (also matches 4430, read the numbers)
tasklist /FI "PID eq 1052"             # which program is PID 1052
netstat -abno                          # program names too (administrator prompt, slow)
netstat -ano 5                         # repeat every 5 seconds until Ctrl+C
Example output · netstat -ano
Active Connections

  Proto  Local Address          Foreign Address        State           PID
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       1012
  TCP    0.0.0.0:3389           0.0.0.0:0              LISTENING       1052
  TCP    203.0.113.10:3389      198.51.100.7:51234     ESTABLISHED     1052
  TCP    203.0.113.10:50122     192.0.2.80:443         TIME_WAIT       0
  UDP    0.0.0.0:3389           *:*                                    1052

-a shows connections and listening ports, -n skips name lookups and -o adds the PID; there is no -p for processes as on Linux, because on Windows -p picks a protocol (netstat -ano -p tcp). -b names the executable behind each line, but only from an elevated prompt, and it can take a while. -r prints the routing table (the same as route print), -s per-protocol statistics and -e interface counters. PID 0 on a TIME_WAIT line is normal: the connection no longer belongs to any process.

PowerShell has the same data as objects, which is easier to filter and count:

PowerShell
Get-NetTCPConnection -State Listen | Sort-Object LocalPort |
  Format-Table LocalAddress, LocalPort, OwningProcess
Get-Process -Id (Get-NetTCPConnection -LocalPort 443 -State Listen).OwningProcess
Get-NetTCPConnection | Group-Object State | Sort-Object Count -Descending |
  Format-Table Count, Name

On a Windows server the usual next step after finding a listener is the firewall: opening a port in Windows Firewall shows how, and the RDP port guide walks through netstat -ano | findstr :3389 on a live RDP server.

netstat on macOS

macOS has the BSD netstat, where -p also means protocol and there is no process column in the usual output. netstat -an -p tcp lists TCP sockets and netstat -rn the routing table; for the program behind a port, use lsof, which macOS ships: sudo lsof -nP -iTCP -sTCP:LISTEN.

Common errors

What you seeCauseFix
netstat: command not foundnet-tools is not installedUse ss -tulpn, or sudo apt install net-tools
(Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.)netstat -p without rootRun it with sudo
- in the PID/Program columnAnother user's process without sudo, or a socket the kernel holds itself (WireGuard, NFS)Run with sudo; a kernel socket has no process to show
ss: command not foundA minimal image without iproute2, such as Alpineapk add iproute2-ss, or BusyBox’s netstat -tulpn
A port you know is open does not appearThe service runs in a container with its own network namespace, and the host forwards the port with firewall rules instead of a listening processRun ss inside the container’s namespace with nsenter, as in the ifconfig guide

Frequently asked

What does netstat -tulpn do?

It lists listening sockets: -t TCP, -u UDP, -l listening only, -p the PID and program name, -n numeric addresses and ports. Run it with sudo, or the processes of other users show a dash instead of a name. On a system without net-tools, ss -tulpn shows the same information.

Is netstat deprecated on Linux?

In practice, yes. Its package, net-tools, is no longer installed by default on current Debian, Ubuntu and Rocky images, and the netstat man page calls the program mostly obsolete. ss replaces it for sockets, ip route for netstat -r and ip -s link for netstat -i. You can still install net-tools if you want netstat back.

How do I find which process uses a port on Windows?

Run netstat -ano | findstr :443 and read the PID in the last column, then tasklist /FI "PID eq 1234" to get the program name. In PowerShell, Get-NetTCPConnection -LocalPort 443 shows the PID in its OwningProcess column, and Get-Process -Id with that PID names the program. findstr :443 also matches ports such as 4430, so read the numbers.

What does CLOSE_WAIT mean in netstat?

The remote side closed the connection, but the local program has not closed its socket yet. A few are normal; a count that keeps growing means the application never closes those sockets, a leak that ends in a too many open files error.

Related articles

All guides