ss und netstat: Netzwerkverbindungen analysieren
$
/etc
Linux · Netzwerk · Systemadministration
ss und netstat: Netzwerkverbindungen analysieren
Verbindungszustände lesen, Ports zuordnen, Konflikte vor dem Start erkennen

Wer einen Dienst nicht startet, weil ein Port bereits belegt ist, oder wissen muss, welcher Prozess wirklich hinter einer Verbindung steckt, kommt an ss nicht vorbei. Dieser Artikel zeigt, warum ss das alte netstat abgelöst hat, wie man Verbindungszustände wie ESTABLISHED und TIME_WAIT richtig liest und wie man Port-Konflikte vor dem Start zuverlässig diagnostiziert.

14 Min. Lesezeit ss · netstat · TCP/IP · Ports Debian · Ubuntu · RHEL

1. Warum Verbindungsanalyse zum Alltag gehört

Auf jedem Linux-Server, der einen Webshop, eine Datenbank oder einen Queue-Consumer betreibt, laufen ständig TCP- und UDP-Verbindungen auf, ab und in wartende Zustände über. Ein PHP-FPM-Pool, das nicht antwortet, eine Datenbankverbindung, die nie geschlossen wird, oder ein Deployment, das mit einer kryptischen Bind-Fehlermeldung abbricht: In all diesen Fällen ist der erste Schritt derselbe, nämlich ein Blick auf die aktuellen Netzwerkverbindungen des Systems. Ohne dieses Werkzeug bleibt die Fehlersuche reines Raten.

Die beiden klassischen Werkzeuge dafür heißen ss und netstat. Beide zeigen offene Sockets, deren Zustand und, mit den passenden Rechten, den dazugehörigen Prozess. Der Unterschied liegt nicht in der grundsätzlichen Aufgabe, sondern in der Umsetzung: Wie schnell liefert das Tool die Daten, wie zuverlässig ist die Ausgabe bei tausenden gleichzeitigen Verbindungen, und wie gut lässt sich das Ergebnis in Skripten weiterverarbeiten. Genau diese Fragen entscheiden im Produktivbetrieb, welches Tool die richtige Wahl ist.

2. ss vs. netstat: Warum ss das alte Tool abgelöst hat

netstat stammt aus dem net-tools-Paket, dessen Entwicklung seit vielen Jahren praktisch stillsteht. Das Tool liest seine Informationen aus den Textdateien unter /proc/net/tcp, /proc/net/tcp6 und /proc/net/udp, parst diese Zeile für Zeile und löst anschließend für jede Verbindung Zusatzinformationen wie den Prozessnamen separat auf. Bei wenigen Dutzend Verbindungen fällt das nicht auf, bei einem stark ausgelasteten Webserver mit zehntausenden gleichzeitigen Sockets wird netstat spürbar langsam.

ss gehört zum iproute2-Paket und spricht direkt mit dem Kernel über Netlink-Sockets, genauer über die inet_diag-Schnittstelle. Der Kernel liefert die Socket-Informationen dabei in einem strukturierten Binärformat statt als Text, wodurch das Parsen entfällt und die Abfrage auch bei sehr vielen Verbindungen in Millisekunden abgeschlossen ist. Seit einigen Jahren ist iproute2 auf praktisch jeder gängigen Distribution vorinstalliert, während net-tools auf minimalen Images wie schlanken Docker-Basis-Images oft fehlt und manuell nachinstalliert werden muss. Aus diesem Grund empfiehlt auch die offizielle Dokumentation vieler Distributionen inzwischen ss als Standardwerkzeug.

3. ss-Grundlagen: Syntax und wichtigste Optionen

Der Aufruf ss [Optionen] [Filter] folgt einem einfachen Schema. Die wichtigsten Optionen lassen sich beliebig kombinieren: -t zeigt TCP-Sockets, -u UDP-Sockets, -l beschränkt die Ausgabe auf lauschende Sockets, -a zeigt zusätzlich alle aktiven Verbindungen, -n unterdrückt die DNS-Auflösung von Adressen und beschleunigt die Ausgabe spürbar, und -p zeigt den Prozessnamen samt PID, benötigt dafür aber Root-Rechte beziehungsweise sudo. Die Kombination ss -tlnp ist damit der Befehl, den man in der Praxis am häufigsten tippt.

Ohne -n versucht ss, jede IP-Adresse per Reverse-DNS in einen Hostnamen aufzulösen. Bei einer Liste mit hunderten Verbindungen summieren sich diese DNS-Anfragen zu einer spürbaren Verzögerung, besonders wenn der DNS-Server selbst langsam antwortet. Das Bash-Pattern für schnelle, skriptfreundliche Abfragen lautet deshalb immer, -n mitzugeben, sobald das Ergebnis maschinell weiterverarbeitet oder unter Zeitdruck gelesen werden soll.


# List all listening TCP sockets with owning process (needs root/sudo)
sudo ss -tlnp

# Example output
State   Recv-Q  Send-Q   Local Address:Port    Peer Address:Port  Process
LISTEN  0       511      0.0.0.0:80             0.0.0.0:*          users:(("nginx",pid=1284,fd=6))
LISTEN  0       4096     127.0.0.1:9000          0.0.0.0:*          users:(("php-fpm8.3",pid=2201,fd=9))
LISTEN  0       128      0.0.0.0:22              0.0.0.0:*          users:(("sshd",pid=901,fd=3))

# All TCP sockets, numeric output, no DNS lookups
ss -atn

# Only currently established connections
ss -tan state established

4. Verbindungszustände lesen: LISTEN, ESTABLISHED, TIME_WAIT

TCP-Verbindungen durchlaufen eine feste Zustandsmaschine, und wer die wichtigsten Zustände kennt, kann eine ss-Ausgabe in Sekunden richtig einordnen. LISTEN bedeutet, dass ein Prozess einen Port gebunden hat und auf eingehende Verbindungen wartet, ohne dass bereits Daten fließen. ESTABLISHED ist eine vollständig aufgebaute Verbindung mit aktivem Datenaustausch in beide Richtungen, der Normalzustand für jede laufende Anfrage. SYN-SENT und SYN-RECV markieren den Drei-Wege-Handshake, der gerade läuft, und sollten in der Regel nur kurz sichtbar sein.

TIME-WAIT tritt auf, nachdem eine Verbindung aktiv geschlossen wurde, und dauert standardmäßig zwei Minuten (zweimal die maximale Segmentlebensdauer). Der Zustand verhindert, dass verspätete Pakete einer alten Verbindung fälschlich einer neuen Verbindung zugeordnet werden. Viele kurze TIME-WAIT-Verbindungen auf einem Webserver mit hohem Anfrageaufkommen sind völlig normal und kein Fehler. CLOSE-WAIT dagegen ist ein wichtiges Warnsignal: Der entfernte Partner hat die Verbindung bereits geschlossen, aber die eigene Anwendung hat den Socket noch nicht geschlossen. Häufen sich CLOSE-WAIT-Einträge über längere Zeit an, deutet das fast immer auf einen Socket-Leak in der Anwendung hin, etwa fehlendes Verbindungsschließen nach einem HTTP-Request in einem PHP-Worker oder einem Backend-Dienst.

5. Welcher Prozess einen Port belegt

Die Frage "Wer hört gerade auf Port 3306?" lässt sich mit einem Filterausdruck direkt beantworten, statt die komplette Liste manuell zu durchsuchen. ss unterstützt eine eigene Filtersyntax mit den Schlüsselwörtern sport und dport für Quell- und Zielport, sodass sich die Ausgabe schon auf Kernel-Ebene einschränken lässt, bevor überhaupt etwas auf dem Bildschirm erscheint. Das ist deutlich effizienter, als die volle Liste auszugeben und anschließend mit grep nach dem gesuchten Port zu filtern.

Ohne sudo zeigt ss -tlnp zwar weiterhin alle lauschenden Ports, die Spalte mit Prozessname und PID bleibt für Sockets fremder Benutzer aber leer, da der Kernel diese Information aus Sicherheitsgründen nur dem Besitzer des Prozesses oder Root preisgibt. Als Alternative eignen sich lsof -i :PORT, das denselben Zweck über die Dateideskriptor-Sicht erfüllt, oder fuser PORT/tcp, das direkt die PID des Prozesses ausgibt, der den Port hält, und sich gut für kurze Ad-hoc-Checks in Skripten eignet.


# Which process owns port 3306 (MySQL)?
sudo ss -tlnp sport = :3306

# Alternative tools if ss is not available
sudo lsof -i :3306
sudo fuser 3306/tcp

# Check before starting a service to avoid a bind failure
sudo ss -ltn sport = :8080 | grep -q LISTEN && echo "Port 8080 is already in use" || echo "Port 8080 is free"

# Real failure from systemd when the port is already taken
sudo systemctl start nginx
# Job for nginx.service failed because the control process exited with error code.
# nginx[1421]: bind() to 0.0.0.0:80 failed (98: Address already in use)

6. Address-already-in-use-Fehler vor dem Start diagnostizieren

Der Fehler bind() to 0.0.0.0:80 failed (98: Address already in use) ist einer der häufigsten Gründe, warum ein Deployment scheitert. Die Ursache ist fast immer dieselbe: Ein anderer Prozess, ein Docker-Container über docker-proxy, oder ein hängender alter Prozess derselben Anwendung belegt den Port bereits. Statt den Dienst blind neu zu starten und auf Besserung zu hoffen, lohnt sich ein gezielter Check mit ss vor jedem Start, gerade in Deployment-Skripten und CI/CD-Pipelines.

In systemd-Units lässt sich dieser Check sogar automatisieren: Eine ExecStartPre-Zeile prüft den Port und bricht mit einer klaren Fehlermeldung im Journal ab, statt dass der Dienst in eine wenig aussagekräftige Restart-Schleife läuft. Das spart im Ernstfall wertvolle Minuten bei der Fehlersuche, weil sofort klar ist, dass ein Portkonflikt und kein Konfigurationsfehler im Dienst selbst vorliegt.


[Unit]
Description=Custom Magento Queue Consumer
After=network.target mysql.service

[Service]
Type=simple
User=magento
# Fail fast with a clear log line instead of a cryptic bind error
ExecStartPre=/bin/sh -c '! ss -ltn sport = :8082 | grep -q LISTEN'
ExecStart=/usr/bin/php /var/www/magento/bin/magento queue:consumers:start async.operations.all
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Ein häufiger Auslöser in containerisierten Umgebungen ist eine falsch aufgeräumte docker-compose.yml: Ein Reverse Proxy bindet Port 80 direkt an den Host, während ein zweiter Dienst denselben Port auf dem Host über eine ältere Compose-Datei ebenfalls beanspruchen will. docker ps --filter "publish=80" zeigt in diesem Fall zuverlässig, welcher Container den Port bereits hält, bevor ss überhaupt zum Einsatz kommt.


# docker-compose.yml: a leftover container is a common cause,
# of "Address already in use" on the host
services:
  varnish:
    image: varnish:7.5
    ports:
      - "80:80"      # binds host port 80 directly
    depends_on:
      - nginx

  nginx:
    image: nginx:1.27
    expose:
      - "8080"

# Find the container holding the host port before starting nginx natively:
# docker ps --filter "publish=80"

7. Filterausdrücke und Verbindungsstatistiken

Die Filtersyntax von ss geht deutlich über einfache Portangaben hinaus. Ausdrücke wie state established, state time-wait oder Kombinationen mit and lassen sich direkt hinter die Optionen schreiben, etwa ss -tan state established '( dport = :443 or sport = :443 )', um gezielt alle aktiven HTTPS-Verbindungen zu isolieren. Diese Filter werden vom Kernel selbst ausgewertet, was insbesondere auf Systemen mit vielen tausend Verbindungen deutlich schneller ist als eine nachgelagerte Filterung mit grep oder awk.

Für einen schnellen Überblick ohne Einzelverbindungen liefert ss -s eine kompakte Statistik: Gesamtzahl der Sockets, aufgeschlüsselt nach TCP, UDP und weiteren Protokollen, sowie die Verteilung der TCP-Verbindungen auf Zustände wie established, closed, orphaned und timewait. Für die maschinelle Weiterverarbeitung, etwa in einem Monitoring-Skript, eignet sich ss -J, das die Socket-Liste als JSON ausgibt und damit robustes Parsen ohne fragile Spaltenzählung ermöglicht.


// ss -J emits machine-readable JSON, stable for scripts and monitoring
$ ss -tlnp -J
{
  "sockets": [
    {
      "local": { "address": "0.0.0.0", "port": 80 },
      "peer": { "address": "0.0.0.0", "port": 0 },
      "state": "LISTEN",
      "process": { "name": "nginx", "pid": 1284 }
    },
    {
      "local": { "address": "127.0.0.1", "port": 9000 },
      "peer": { "address": "0.0.0.0", "port": 0 },
      "state": "LISTEN",
      "process": { "name": "php-fpm8.3", "pid": 2201 }
    }
  ]
}

8. netstat: Wann das Legacy-Tool noch sinnvoll ist

Trotz aller Nachteile ist netstat nicht wertlos. Auf sehr minimalen Systemen, alten Appliances oder in Legacy-Container-Images ohne iproute2 ist netstat mitunter das einzig verfügbare Werkzeug. Die Ausgabe von netstat -s liefert zudem seit Jahrzehnten dasselbe vertraute Format mit detaillierten Protokollstatistiken, etwa zu retransmittierten TCP-Segmenten oder verworfenen ICMP-Paketen, das viele erfahrene Administratoren aus Gewohnheit weiterhin gut lesen können.

Problematisch wird es, wenn alte Monitoring- oder Deployment-Skripte die Textausgabe von netstat mit grep und awk zeilenweise zerlegen. Solche Skripte brechen bei jeder kleinen Änderung der Spaltenbreite oder Lokalisierung. Wer bestehende Skripte modernisiert, sollte sie schrittweise auf ss -H, das die Kopfzeile unterdrückt, oder auf ss -J für strukturiertes JSON umstellen. Beide Varianten liefern ein stabiles, versioniertes Ausgabeformat, das sich nicht bei jedem Distributions-Update ändert, und machen Automatisierung damit deutlich robuster.

9. ss und netstat im direkten Vergleich

Für die tägliche Praxis lohnt sich eine direkte Gegenüberstellung der gebräuchlichsten Befehle. Wer netstat-Gewohnheiten aus älteren Skripten oder aus der Ausbildung mitbringt, findet hier die jeweilige ss-Entsprechung, inklusive des konkreten Vorteils im Produktivbetrieb.

Aufgabe netstat (veraltet) ss (empfohlen) Vorteil
Lauschende TCP-Ports anzeigen netstat -tlnp ss -tlnp Netlink statt /proc-Parsing, deutlich schneller
Prozess hinter Port finden netstat -tulpn | grep :80 ss -tlnp sport = :80 Kernel-Filter statt nachgelagerter Textsuche
Verbindungsstatistiken netstat -s ss -s Kompaktere, aktuelle Kernel-Zähler
Etablierte Verbindungen zählen netstat -ant | grep ESTABLISHED | wc -l ss -tan state established | wc -l Kein Parsen von Freitext nötig
UNIX-Sockets auflisten netstat -x ss -x Gleiche Filtersyntax wie bei TCP/UDP

Der Trend in der Tabelle ist eindeutig: Überall dort, wo netstat auf Textverarbeitung mit grep oder awk angewiesen ist, bietet ss einen nativen Filterausdruck, der vom Kernel direkt ausgewertet wird. Das reduziert nicht nur die Laufzeit, sondern auch die Fehleranfälligkeit von Skripten, die auf einer stabilen Ausgabe angewiesen sind.

Mironsoft

Server-Diagnose, Deployment-Absicherung und Linux-Infrastruktur

Portkonflikte und hängende Verbindungen im Griff?

Wir analysieren eure Server-Infrastruktur, identifizieren Portkonflikte und Socket-Leaks und bauen belastbare Vorab-Checks in Deployment- und systemd-Prozesse ein, damit Address-already-in-use-Fehler nicht mehr im Produktivbetrieb auftauchen.

Server-Audit

Vollständige Analyse offener Ports, Prozesse und Verbindungszustände

Deployment-Härtung

Port-Checks in systemd-Units und CI/CD-Pipelines nachrüsten

Monitoring-Integration

ss -J und strukturierte Verbindungsdaten in bestehende Monitoring-Systeme einbinden

10. Zusammenfassung

ss und netstat lösen dieselbe Grundaufgabe, nämlich Netzwerkverbindungen sichtbar zu machen, aber ss tut dies über Netlink direkt im Kernel und damit schneller und zuverlässiger als das textbasierte netstat. Verbindungszustände wie LISTEN, ESTABLISHED und TIME-WAIT beschreiben normale Phasen einer TCP-Verbindung, während sich häufende CLOSE-WAIT-Einträge fast immer auf einen Fehler in der Anwendung zurückführen lassen. Mit ss -tlnp und gezielten Filterausdrücken lässt sich in Sekunden klären, welcher Prozess einen Port belegt, noch bevor ein Deployment mit einem kryptischen Bind-Fehler abbricht.

Der größte praktische Nutzen entsteht, wenn dieser Check nicht erst beim Debugging, sondern präventiv in Deployment-Skripten und systemd-Units eingebaut wird. Eine ExecStartPre-Prüfung, die einen belegten Port sofort mit einer klaren Meldung im Journal quittiert, spart in der Praxis regelmäßig wertvolle Minuten gegenüber dem manuellen Debugging eines fehlgeschlagenen Service-Starts. netstat bleibt als Fallback auf minimalen Systemen relevant, sollte aber in aktiv gepflegten Skripten schrittweise durch ss -H oder ss -J ersetzt werden.

ss und netstat: Das Wichtigste auf einen Blick

ss statt netstat

Netlink-basiert, deutlich schneller bei vielen Sockets und Teil des vorinstallierten iproute2-Pakets auf fast jeder Distribution.

Zustände richtig lesen

TIME-WAIT ist normal nach dem Verbindungsende, häufende CLOSE-WAIT-Einträge deuten fast immer auf einen Socket-Leak hin.

Prozess pro Port finden

sudo ss -tlnp sport = :PORT zeigt Prozessname und PID direkt, ohne Textfilterung mit grep.

Konflikte vorbeugen

Port-Check als ExecStartPre in systemd-Units oder als Vorabschritt im Deployment-Skript verhindert kryptische Bind-Fehler.

11. FAQ: ss und netstat für Netzwerkverbindungen

1Warum ist ss schneller als netstat?
ss fragt Socket-Informationen über Netlink direkt vom Kernel ab, während netstat Textdateien unter /proc/net zeilenweise parst. Bei vielen Verbindungen macht sich das deutlich bemerkbar.
2Ist netstat noch installiert?
Nicht immer. Viele aktuelle Distributionen und schlanke Docker-Images liefern nur iproute2 mit ss aus, netstat muss oft über net-tools nachinstalliert werden.
3Prozess hinter einem Port finden?
sudo ss -tlnp sport = :PORT zeigt den lauschenden Prozess samt PID. lsof -i :PORT oder fuser PORT/tcp liefern dieselbe Information.
4Was bedeutet TIME_WAIT?
Zustand nach dem aktiven Schließen einer Verbindung, standardmäßig zwei Minuten. Verhindert Fehlzuordnung verspäteter Pakete und ist auf belebten Servern normal.
5Was bedeutet CLOSE_WAIT?
Der entfernte Partner hat geschlossen, die eigene Anwendung den Socket aber noch nicht. Häufende Einträge deuten fast immer auf einen Socket-Leak hin.
6Address already in use vor dem Start prüfen?
sudo ss -ltn sport = :PORT vor dem Start ausfuehren. In systemd-Units als ExecStartPre automatisierbar, bricht mit klarer Meldung ab statt in einer Restart-Schleife zu hängen.
7ss ohne Root-Rechte nutzen?
Sockets werden weiterhin angezeigt, die Prozessspalte bleibt für fremde Benutzer aber leer. Prozessinformationen gibt der Kernel nur dem Besitzer oder Root frei.
8ss -s vs. netstat -s?
ss -s liefert eine kompakte Zusammenfassung nach Protokoll und Zustand. netstat -s zeigt detailliertere, langsamer erhobene Protokollstatistiken. Für einen schnellen Überblick reicht meist ss -s.
9Nach Ziel- oder Quellport filtern?
Mit dport und sport, zum Beispiel ss -tan dport = :443 oder ss -tlnp sport = :80. Der Kernel wertet diese Filter direkt aus.
10Ersetzt ss auch netstat -r?
Nein, dafür ist ip route zuständig. ss beschränkt sich auf Socket-Informationen, ip route und ip addr ersetzen netstat -r und ifconfig.