Quick take: tcpdump captures network packets from a live interface or a saved file. Filter by host, port, or protocol using BPF expressions. Use -w to save a PCAP file and -r to read one. Add -nn to skip DNS lookups and see raw addresses.
Introduction
There is a moment every infrastructure engineer knows: something is wrong with the network, the application logs say nothing useful, and you need to see what is actually travelling between two machines. tcpdump is the tool for that moment. It puts your network interface into promiscuous mode, captures every packet crossing it, and either prints what it sees or saves it to a file you can analyse later.
I have used tcpdump in situations where no other tool would tell me what was happening — a load balancer that was silently dropping connections, a misconfigured firewall that was rejecting packets without logging, a containerised service whose health-check responses never made it back. In each case, a focused tcpdump capture on the right interface showed me the truth in under five minutes. That is what this guide is about: using tcpdump the way working engineers use it, not the way a manual page presents it.
tcpdump is available on every mainstream Linux distribution and on macOS. On headless servers where you cannot install Wireshark, it is often the only packet-level diagnostic tool you have. Learning it well pays dividends for as long as you work with Linux infrastructure.
Installing tcpdump
On most systems tcpdump is pre-installed. If yours does not have it:
# Debian, Ubuntu
sudo apt install tcpdump
# RHEL, CentOS, AlmaLinux, Rocky Linux
sudo dnf install tcpdump
# Arch Linux
sudo pacman -S tcpdumpVerify the version after installing:
tcpdump --versionBy default, running tcpdump requires sudo because opening a raw socket needs the CAP_NET_RAW Linux capability. If you want to allow a specific non-root user to capture without full sudo, you can grant the capability directly to the binary — but on shared systems, be careful about who gets this access since packet captures can expose credentials sent in plaintext.
Syntax
The basic syntax of the tcpdump command is:
tcpdump [OPTIONS] [FILTER EXPRESSION]The filter expression is a Berkeley Packet Filter (BPF) expression — a powerful mini-language for describing exactly which packets you want. Without a filter, tcpdump captures every packet on the selected interface, which on a busy server will scroll faster than you can read. You almost always want a filter.
How tcpdump Works
When you run tcpdump, the kernel copies matching packets from the network driver into a ring buffer before they are passed up the network stack. This happens at the kernel level, which is why tcpdump can see packets that are dropped by iptables rules — it captures them before the rules are applied on ingress, and after they are generated on egress. This distinction matters: if you are debugging why packets are not reaching a service, tcpdump can tell you whether they arrived at the interface at all.
The packet timestamps tcpdump prints come from the kernel, not from user space, so they are accurate to microsecond resolution on most systems. Each line in the output represents one packet and includes the timestamp, protocol, source, destination, and a decoded summary of the packet headers. The level of decoding depends on the protocol — TCP and UDP get full header decoding, HTTP and DNS get human-readable field parsing when you use -A or -X, and raw binary gets printed as hex or ASCII.
Understanding that tcpdump operates on raw packets — not on application-level connections — is key to using it correctly. A TCP connection is made up of many packets including SYN, SYN-ACK, ACK, data segments, and FIN/RST. When you capture on a busy interface without filtering, you will see all of this interleaved across dozens of simultaneous connections. That is why targeted BPF filters are not optional — they are the technique that turns noise into signal.
Your First Packet Capture
Start with the simplest possible capture on your primary network interface to see traffic moving:
# Find your interface names first
ip link show
# Capture 10 packets on eth0
sudo tcpdump -i eth0 -c 10
# Capture on any interface
sudo tcpdump -i any -c 10The output will look something like this:
14:32:01.123456 IP 10.0.0.1.22 > 192.168.1.5.54321: Flags [P.], seq 1:53, ack 1, win 502, length 52
14:32:01.123789 IP 192.168.1.5.54321 > 10.0.0.1.22: Flags [.], ack 53, win 2048, length 0Each field matters: the timestamp, the protocol (IP), the source address and port, the destination address and port, the TCP flags in brackets, and the payload length. The flags [P.] mean PSH+ACK — the server is pushing data and acknowledging the last packet it received. [.] is a pure ACK. [S] is SYN, [R] is RST, [F] is FIN.
The -nn flag is something you should almost always add. Without it, tcpdump tries to resolve IP addresses to hostnames and port numbers to service names (like 80 to http). This resolution adds latency to each printed line and can cause the output buffer to back up on a busy interface. With -nn, you see raw numbers immediately:
sudo tcpdump -i eth0 -nn -c 10Filtering Traffic with BPF Expressions
BPF filter expressions are what make tcpdump useful rather than overwhelming. You can filter by host, net, port, protocol, direction, and combinations of all of these using and, or, and not.
# Traffic to or from a specific host
sudo tcpdump -i eth0 host 10.0.0.5
# Only traffic FROM a host
sudo tcpdump -i eth0 src host 10.0.0.5
# Only traffic TO a host
sudo tcpdump -i eth0 dst host 10.0.0.5
# All traffic on port 80
sudo tcpdump -i eth0 port 80
# HTTPS traffic to a specific server
sudo tcpdump -i eth0 host 10.0.0.20 and port 443
# Everything except SSH (port 22)
sudo tcpdump -i eth0 not port 22
# Only UDP traffic
sudo tcpdump -i eth0 udp
# DNS queries (UDP port 53)
sudo tcpdump -i eth0 udp port 53
# Entire subnet
sudo tcpdump -i eth0 net 192.168.1.0/24
# ICMP only (ping traffic)
sudo tcpdump -i eth0 icmpThe not port 22 filter is one I use constantly when troubleshooting a server I am connected to over SSH. Without it, every SSH keepalive and terminal keystroke floods the output and buries the traffic you are trying to see. Always exclude your own SSH session when capturing on a remote server.
You can combine multiple conditions with parentheses, but remember to quote the entire expression in single quotes when it contains parentheses or characters the shell might interpret:
# HTTP or HTTPS traffic from one specific client
sudo tcpdump -i eth0 'src host 10.0.0.5 and (port 80 or port 443)'
# Any TCP traffic with SYN flag set (new connection attempts)
sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0'
# TCP RST packets — connections being refused or killed
sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-rst != 0'The tcp[tcpflags] syntax lets you inspect specific bits inside the TCP header. Capturing RST packets is extremely useful for debugging — an unexpected stream of RSTs usually points to a firewall rule, a service crash, or a client sending to a port nothing is listening on.
Common Options and Flags
| Option | Description |
|---|---|
| -i IFACE | Interface to listen on. Use any for all interfaces. |
| -nn | Do not resolve IP addresses or port numbers to names (faster output). |
| -c N | Stop after capturing N packets. |
| -w FILE | Write raw packets to a PCAP file instead of printing. |
| -r FILE | Read from a saved PCAP file instead of a live interface. |
| -v / -vv / -vvv | Increase verbosity of protocol decoding. |
| -A | Print each packet as ASCII — useful for reading HTTP payloads. |
| -X | Print each packet in hex and ASCII — useful for binary protocols. |
| -s SNAPLEN | Capture only the first SNAPLEN bytes of each packet (default 262144). |
| -G SECS | Rotate the output file every SECS seconds (use with -w). |
| -W N | Limit rotation to N files, then overwrite from the start (use with -G). |
| -l | Line-buffer output — useful when piping tcpdump into grep or awk. |
| -D | List all available network interfaces. |
| -e | Print the Ethernet MAC addresses (layer 2 header) on each line. |
| -t | Suppress the timestamp on each line. |
| -q | Quiet output — less protocol detail, shorter lines. |
Practical Examples
These are the captures I actually run when diagnosing infrastructure problems:
# Watch HTTP requests as they arrive — read request lines in ASCII
sudo tcpdump -i eth0 -A -nn port 80 | grep -E 'GET|POST|Host:'
# Debug DNS — see every query and response
sudo tcpdump -i eth0 -nn -vv udp port 53
# Check whether a database connection is reaching the server
sudo tcpdump -i eth0 -nn host 10.0.0.10 and port 5432
# See all new TCP connections (SYN packets) in real time
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] == tcp-syn'
# Capture ICMP to debug ping failures
sudo tcpdump -i eth0 -nn icmp
# Watch traffic on a Docker bridge interface
sudo tcpdump -i docker0 -nn
# Monitor a specific container's traffic by its veth pair
sudo tcpdump -i veth1a2b3c -nn
# Count packets per second on port 443 (run for 10 seconds)
sudo tcpdump -i eth0 -nn port 443 -c 1000 2>&1 | tail -3The Docker bridge examples are something I use regularly when debugging microservices. Each container gets a virtual Ethernet interface on the host side — find its name with ip link show and you can capture the container's traffic directly without any changes to the container image.
For web servers, the ASCII mode with grep is a quick way to see what HTTP requests are actually arriving at your server, not what your application thinks it received. If your app is returning 400 errors and the path looks wrong, capturing on the interface often shows the raw HTTP request and reveals encoding issues or proxy header mutations.
Saving and Reading PCAP Files
For any capture you want to examine later — or share with someone who has Wireshark — save to a PCAP file:
# Capture 60 seconds of all non-SSH traffic and save it
sudo tcpdump -i eth0 -nn not port 22 -w /tmp/capture.pcap
# Read back and filter the saved file — no interface needed
sudo tcpdump -r /tmp/capture.pcap host 10.0.0.5
# Read and print with full ASCII decode
sudo tcpdump -r /tmp/capture.pcap -A port 80
# Rotate files every 300 seconds, keep last 12 (one hour of history)
sudo tcpdump -i eth0 -w /var/captures/traffic-%Y%m%d-%H%M%S.pcap -G 300 -W 12The rotation pattern with -G and -W is useful for ongoing monitoring. It gives you a rolling window of capture history without filling the disk. On a busy 1Gbps interface, an unfiltered capture can fill a disk in minutes, so always apply a filter and set a capture limit or rotation when doing long-term captures.
PCAP files are the standard interchange format for packet captures. Wireshark, tshark, tcpreplay, and many other tools all read the same format. A practical workflow I use for complex protocol debugging: run tcpdump on the remote server with -w, download the PCAP with scp, and open it in Wireshark on my laptop where I can follow TCP streams, filter by conversation, and look at protocol dissections with a GUI.
Understanding tcpdump Output
Let us break down a real tcpdump line in detail so you can read any output confidently:
14:32:01.984321 IP 10.0.0.5.55234 > 10.0.0.1.80: Flags [S], seq 3247891234, win 65495, options [mss 1460,sackOK,TS val 1234 ecr 0,nop,wscale 7], length 0Breaking this down: 14:32:01.984321 is the timestamp. IP is the protocol (IPv4). 10.0.0.5.55234 is source address and source port — note the port is appended with a dot, not a colon. 10.0.0.1.80 is destination. Flags [S] — this is a SYN packet, the first step of a TCP handshake. seq 3247891234 is the starting sequence number. win 65495 is the advertised receive window size. The options field shows TCP extensions the client supports: MSS negotiation, SACK, timestamps, and window scaling. length 0 means no payload — which is correct for a SYN, which carries no data.
When you see Flags [S.] in response, that is the SYN-ACK from the server. Flags [.] completes the handshake. If you see Flags [S] repeating several times from the same source without any [S.] response, the connection is being refused or the SYN packets are not reaching the server. If you see Flags [R.], the connection was reset — something terminated it abruptly.
tcpdump in Production Environments
Running tcpdump on a production server requires care. On a high-traffic interface without a filter, tcpdump will consume significant CPU just to keep up with the packet rate and print output. Always apply a tight BPF filter first and consider using -s 96 to capture only the first 96 bytes of each packet — enough for headers and the beginning of application data, but not the full payload, which reduces the data rate significantly.
For security-sensitive environments, be aware that tcpdump captures can contain passwords, session tokens, and other sensitive data if the traffic is unencrypted. On an HTTPS server you will only see encrypted TLS records, not the plaintext HTTP inside them, but on any service that still uses plaintext — internal APIs, database connections over plain TCP, old HTTP endpoints — a capture will contain real credentials. Handle PCAP files from production like you handle database backups: encrypt them in transit, restrict access, and delete them when you are done.
One pattern I use on busy servers is to combine tcpdump with a tight filter and pipe the output through grep with line-buffering to extract only the specific events I am looking for, without storing the full capture:
# Print a line every time a new TCP connection opens to port 8080
sudo tcpdump -i eth0 -l -nn 'tcp[tcpflags] == tcp-syn and dst port 8080' | \
awk '{print strftime("%H:%M:%S"), $0}'
# Count connection attempts per source IP over 30 seconds
sudo tcpdump -i eth0 -nn -c 500 'tcp[tcpflags] == tcp-syn' 2>/dev/null | \
awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rnThe second command is useful for detecting a SYN flood or aggressive client. I have used it to identify a misconfigured load balancer that was sending health checks far too frequently, essentially brute-forcing its own backend with connection attempts.
Common Mistakes
The most common mistake is capturing without a filter on a busy interface. The output scrolls so fast it is unreadable and the disk fills if you are writing to a file. Always start with a filter. If you do not know what you are looking for yet, start with not port 22 and a short time window, then refine from there.
A second mistake is forgetting -nn. Without it, tcpdump makes a DNS reverse-lookup for every IP address it sees. On a server that has lots of connections from many different addresses, this creates a cascade of DNS queries that appear in your own capture, polluting the output. It also slows down the output enough that packets can be dropped if the interface is busy. Always use -nn unless you specifically want name resolution.
Another pitfall is not accounting for the interface. On systems with multiple network interfaces — a common situation on cloud instances with a management interface and a data interface — capturing on eth0 may miss traffic on eth1. Use -i any if you are unsure which interface the traffic is using, though note that any disables promiscuous mode and the packet layer information changes slightly.
Tips and Best Practices
- Always include
-nnto skip name resolution and get faster, cleaner output on busy interfaces. - Exclude your own SSH session with
not port 22to keep the output readable when connected remotely. - Use
-c Nto limit capture count or-Gwith-Wfor timed rotation so you never accidentally fill a disk. - Pipe tcpdump output through
-l(line buffer) when chaining with grep or awk, otherwise buffering will delay the output. - For TLS-encrypted traffic, tcpdump shows the TLS handshake metadata — cipher suite, certificate SNI, protocol version — even though it cannot decrypt the payload. This alone is often enough to confirm whether a TLS connection is being established correctly.
- When sharing a capture for debugging, use
-s 96to capture only headers if the payload is sensitive or irrelevant. - Combine tcpdump with
tshark(Wireshark's command-line sibling) for richer protocol dissection on servers where Wireshark's GUI is unavailable.
Final Thoughts
tcpdump is one of those tools that feels intimidating the first time you use it — the output is dense, the filter syntax is unfamiliar, and on a busy interface everything scrolls past in a blur. But once you get used to the BPF filter expressions and the packet flag notation, it becomes the fastest way to answer the question "is this traffic actually arriving?" It cuts through application logs, firewall dashboards, and monitoring abstractions and shows you what is happening at the wire level.
The commands you will use 90% of the time are simple: sudo tcpdump -i eth0 -nn not port 22 host X to watch traffic to a host, port N to watch a service, -w file.pcap to save for later, and -A to read plaintext payloads. Start with those and build up to the BPF flag-level filters as you need them. Every infrastructure engineer should be comfortable with tcpdump — it has saved more debugging sessions than I can count.
FAQ: tcpdump Command in Linux
Do I need root to run tcpdump?+
Yes, by default you need root or sudo to capture raw packets. On Linux you can also grant the CAP_NET_RAW capability to the tcpdump binary with setcap so non-root users can capture without full sudo.
How do I capture traffic on a specific port with tcpdump?+
Use tcpdump -i eth0 port 80 to capture all HTTP traffic on port 80. Combine with host for a specific machine: tcpdump -i eth0 host 10.0.0.5 and port 443.
How do I save tcpdump output to a file for Wireshark?+
Use the -w flag: tcpdump -i eth0 -w capture.pcap. The resulting PCAP file opens directly in Wireshark for graphical analysis.
How many packets does tcpdump capture by default?+
tcpdump captures indefinitely until you press Ctrl+C. Use -c N to stop after N packets, or -G seconds with -W files to rotate output files on a timer.
What is the difference between tcpdump and Wireshark?+
tcpdump is a command-line tool that runs anywhere Linux does, including headless servers and minimal container images. Wireshark is a GUI tool ideal for deep protocol analysis. A common workflow is to capture with tcpdump on the server and analyse the PCAP file in Wireshark on a desktop.
Need help with Linux servers or infrastructure?
Work directly with Muhammad Irfan Aslam for Linux, Ubuntu, Docker, DevOps, cloud, CI/CD, or infrastructure support.
Hire Me for Support