When I first started managing servers, I’d see others using netstat and just follow along. It was a habit picked up from old tutorials, and I never questioned it. Until I needed to debug slow connections on a production server with a few thousand open sockets — netstat took over 30 seconds just to return results. That day, I finally took a serious look at ss.
I manage the network for a 50-person office and a small datacenter — this article is drawn from about 6 months of gradually transitioning from netstat to ss, and learning how to combine both tools for different scenarios.
netstat vs ss: Two Tools, One Goal
Both show you network connection states, listening ports, and active sockets. But how they work under the hood is completely different.
netstat is part of the net-tools package and reads information from /proc/net/ the traditional way. On Ubuntu 20.04+ and Debian 11+, it’s no longer pre-installed — you have to manually install it if you need it.
ss (socket statistics) is part of the iproute2 package and communicates directly with the kernel via netlink sockets. This is why it’s noticeably faster when there are many open connections — instead of parsing text files in /proc, it pulls data straight from the kernel.
Pros and Cons of Each Tool
netstat: Familiar but Outdated
Pros:
- Syntax I remember without Googling; 2012 StackOverflow tutorials still work fine
- Output is easy to read for beginners — clear columns, little explanation needed
- View routing tables and interface statistics in one tool (though
ip routedoes it better)
Cons:
- Slow with many connections — parses
/proc/net/tcpas plain text, doesn’t scale - The
net-toolspackage is barely maintained; many distros have dropped it from default installs - Far fewer and less flexible filter options compared to
ss
ss: Fast and Modern, but Takes Getting Used To
Pros:
- On a server with 5,000+ sockets,
ssreturns results in under a second;netstatcan take a full minute - Very powerful filter expression language — filter by IP, subnet, port, state, and process in a single command
- Shows additional TCP timer and congestion window info — things
netstatsimply doesn’t have - Actively developed and is the standard tool on every modern Linux distro
Cons:
- Filter syntax is completely different from
netstat— takes a few sessions to get comfortable with - Output looks a bit unfamiliar at first, especially the Process column with its
users:(("nginx",pid=5678,fd=7))format
Which Tool for Which Situation?
After 6 months using both, I’ve settled on a fairly simple rule:
- Production server with many connections: Use
ss— no debate. On a server with thousands of open connections, ss returns results in seconds while netstat can take a full minute. - Quick debugging on a dev machine or workstation: Either works, but I’ve been gradually moving to
ssto keep habits consistent. - Need routing tables or interface statistics: Use
ip routeandip -s linkfrom iproute2 instead ofnetstat -r— same package asss, more consistent.
Practical Usage Guide
Check Listening Ports
The task I do most often — see which service is holding which port:
# Using ss (recommended)
ss -tlnp
# Flag explanation:
# -t : TCP only
# -l : listening sockets
# -n : show port numbers instead of service names (faster)
# -p : show process name and PID
# Equivalent netstat command
netstat -tlnp
Output from ss -tlnp looks like this:
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=5678,fd=6))
LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=5678,fd=7))
Find Which Process Is Holding a Specific Port
The most common scenario: a service fails to start because a port is already in use:
# Check which process is using port 8080
ss -tlnp | grep :8080
# Or use ss filter expression
ss -tlnp 'sport = :8080'
# Output will look like: users:(("node",pid=12345,fd=10))
# Kill that process with:
kill -9 12345
View All Active Connections
# All ESTABLISHED TCP connections
ss -tn state established
# Count connections by state
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
# Quick overview with ss -s
ss -s
The ss -s output is very useful for a quick server health check:
Total: 234 (kernel 312)
TCP: 45 (estab 23, closed 5, orphaned 0, timewait 17)
UDP: 8
Filter Connections by IP or Subnet
I use this a lot when managing the office network — checking which machines are connecting to internal servers, or seeing what traffic from a specific IP is hitting which ports:
# Show all connections from subnet 192.168.1.0/24
ss -tn 'dst 192.168.1.0/24'
# Connections to a specific IP
ss -tn 'dst 192.168.1.100'
# Connections from a specific IP
ss -tn 'src 10.0.0.5'
# Combined: connections from subnet to port 443
ss -tn 'src 192.168.1.0/24 and dport = :443'
View TCP Timers — A Feature Exclusive to ss
# View TCP timers (keepalive, retransmit timeout...)
ss -tn -o
# Output will include an extra timer column:
# timer:(keepalive,1min3sec,0)
# Meaning: keepalive timer has 1 min 3 sec remaining, 0 retransmits
Real-time Monitoring
# Update every 2 seconds
watch -n 2 'ss -s'
# Or monitor connection count by state
watch -n 2 'ss -tan | awk "NR>1 {print \$1}" | sort | uniq -c | sort -rn'
Debugging Workflow for Abnormal Connections
When I discovered a server in the datacenter being port-scanned from an unknown IP, here’s the debug process I followed:
# Step 1: Check for SYN flood
ss -tn state syn-recv
# Step 2: Count connections by source IP — detect flooding IPs
ss -tn | awk 'NR>1 {print $5}' | grep -oP '^[\d.]+' | sort | uniq -c | sort -rn | head -20
# Step 3: View all connections from suspicious IP
ss -tn 'src 203.0.113.50'
# Step 4: Check for abnormal TIME_WAIT count
ss -tan state time-wait | wc -l
With netstat, step 2 would take a full minute when the server had many open connections. This is the real reason I switched to ss — not because some blog said it was great, but because waiting for output while debugging a live incident is genuinely frustrating.
Handy Aliases for Daily Use
These three aliases I add to ~/.bashrc on every server — saves quite a bit of typing:
# Add to ~/.bashrc
alias ports='ss -tlnp' # View listening ports
alias conns='ss -tn state established' # Active connections
alias socksum='ss -s' # Socket statistics overview
# Reload
source ~/.bashrc
Installation If Not Already Present
# Debian/Ubuntu
sudo apt install iproute2 # ss (usually pre-installed)
sudo apt install net-tools # netstat (if needed)
# CentOS/RHEL/Rocky Linux
sudo dnf install iproute # ss
sudo dnf install net-tools # netstat
# Check version
ss -V
netstat --version
On Ubuntu 22.04 and Debian 12, ss comes pre-installed. netstat does not — you’ll need to install it separately if required.
Conclusion
Starting from scratch? Learn ss from the start and skip netstat. The syntax is a bit different but worth the time investment. Already comfortable with netstat and want to switch? Memorizing a handful of core ss commands covers 90% of everyday tasks.
For me, after half a year running ss on production, I haven’t gone back to netstat. Not because anyone told me to — but because it’s faster and the filtering is more powerful exactly when I actually need it.

