| Tested on | RHEL 10.2 (Coughlan) — vm1.lab.example (192.168.56.116); lab peer 192.168.56.220 on host-only enp0s8; default gateway 10.0.2.2 on enp0s3 |
|---|---|
| Package | iperf3 3.17.1-6.el10_2curl 8.12.1-4.el10ethtool 6.15-2.el10iproute 6.17.0-2.el10iputils 20240905-5.el10mtr 0.95-11.el10 |
| Applies to | Ubuntu, Debian, Kali Linux, Linux Mint, Pop!_OS, Raspberry Pi OS, elementary OS, Zorin OS, Parrot OS, MX Linux, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Arch Linux |
| Privilege | Normal user for ping, curl, and read-only ip / ethtool; sudo or root for iperf3 server on privileged ports and interface changes |
| Scope | Diagnose Linux slow ethernet and download speed using throughput tests, latency and loss checks, ethtool link speed, interface counters, MTU probes, and route selection. Does not cover Wi-Fi driver tuning, CDN selection, or full packet loss deep dives beyond latency basics. |
| Related guides | Linux packet loss troubleshooting Network is unreachable ip route command Test port connectivity traceroute command |
Downloads crawl, scp takes forever, and the browser spinner outlasts your coffee — but “slow network” on Linux can mean a 100 Mb/s link, congestion on one hop, a wrong route, or a remote server that answers slowly. Measure throughput first, then check whether latency, link speed, drops, MTU, or routing explain the gap.
Measure the actual network throughput
Subjective “feels slow” is not a benchmark. Start with a repeatable download test, then use iperf3 when you control both ends of the path.
HTTP downloads through curl reflect real-world TCP behavior — DNS, TLS, and the remote server included:
curl -o /dev/null -s -w "Downloaded %{size_download} bytes in %{time_total}s (%{speed_download} B/s)\n" http://speedtest.tele2.net/1MB.zipDownloaded 1048576 bytes in 4.050602s (258869 B/s)Roughly 250 KiB/s on this lab NAT path is the baseline to compare after you change cables, routes, or firewall rules. Pick a test file size your link can finish in a few seconds — 1 MiB is enough for a quick check.
For point-to-point TCP without HTTP overhead, run iperf3 in server mode on the receiving host:
iperf3 -sFrom the sender, point the client at that host (iperf3 -c PEER -t 5 -f m). The lab captured the output format on loopback — expect far lower bitrates on a real LAN or WAN:
iperf3 -c 127.0.0.1 -t 3 -f m[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-3.00 sec 14.5 GBytes 41569 Mbits/sec 9 sender
[ 5] 0.00-3.00 sec 14.5 GBytes 41564 Mbits/sec receiver
iperf Done.Read the Bitrate column on the receiver line — that is the sustained TCP throughput for the interval. Non-zero Retr means retransmits; occasional retries are normal on the internet, but hundreds per second on a quiet LAN point at loss or buffer pressure.
Check latency and packet loss
High latency and loss cap throughput even when ethtool reports gigabit — TCP backs off when packets disappear. Use ping for a quick RTT average and loss percentage on the same path you measured above:
ping -c 10 -i 0.2 192.168.56.220--- 192.168.56.220 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 1822ms
rtt min/avg/max/mdev = 0.685/1.055/1.999/0.379 msSub-millisecond average RTT with 0% packet loss on the LAN peer is a healthy baseline. Loss or double-digit millisecond RTT on a host-only segment deserves a look at cables and switch ports before you tune TCP elsewhere.
For intermittent loss on longer paths, mtr combines traceroute with repeated probes:
mtr -rw -c 5 192.168.56.220Start: 2026-08-22T09:16:40+0530
HOST: vm1.lab.example Loss% Snt Last Avg Best Wrst StDev
1.|-- 192.168.56.220 0.0% 5 0.9 1.3 0.9 1.8 0.4See Linux packet loss troubleshooting when Loss% climbs above zero on a path that should be clean.
Check link speed and duplex
A NIC negotiated to 100 Mb/s half-duplex on a gigabit switch caps speed far below what the cable supports. ethtool reports what the driver actually negotiated:
sudo ethtool enp0s8Speed: 1000Mb/s
Duplex: Full
Link detected: yes1000Mb/s and Full match a healthy gigabit Ethernet link. 100Mb/s, Half, or Link detected: no explain slow transfers that have nothing to do with CPU load — fix cabling, switch port, or autoneg before chasing application settings.
Wi-Fi interfaces use different tools (iw dev wlan0 link), but the idea is the same: confirm the PHY rate before you blame the server.
Check interface errors and drops
Kernel counters show whether frames are discarded on the NIC or in the transmit queue while ethtool still reports link up. Inspect the interface that carries the slow traffic:
ip -s link show enp0s83: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
RX: bytes packets errors dropped missed mcast
718124 5475 0 0 0 163
TX: bytes packets errors dropped carrier collsns
29412516 24090 0 3 0 0Watch errors, dropped, and carrier:
- Rising
errors— electrical or driver problems - Rising
dropped— buffer or qdisc pressure (fq_codeldrops under load) - Non-zero
carrier— link flaps
Flat counters during a slow iperf3 run suggest the bottleneck is elsewhere — upstream congestion, a rate limit, or the remote endpoint.
Check MTU
An MTU mismatch makes large TCP segments fail while tiny ping probes succeed — downloads stall or crawl. Confirm the interface MTU first:
ip link show enp0s8 | grep mtu3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000mtu 1500 is standard Ethernet. Probe the path with do-not-fragment ICMP — payload 1472 bytes fills a 1500-byte frame including headers:
ping -c 3 -M do -s 1472 192.168.56.220--- 192.168.56.220 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1003msAll replies returned means this LAN segment handles full-size frames. VPN and tunnel interfaces often use mtu 1400 or lower — if large transfers fail only through the tunnel, lower the inner MTU or enable TCP MSS clamping on that interface.
Check routes
Traffic sent out the wrong interface hits a slow or asymmetric path. ip route get shows which NIC and source IP the kernel picks for a destination:
ip route get 192.168.56.220192.168.56.220 dev enp0s8 src 192.168.56.116 uid 0
cacheLAN peers should use the connected subnet device — here enp0s8. A remote address should exit through your intended gateway:
ip route get 8.8.8.88.8.8.8 via 10.0.2.2 dev enp0s3 src 10.0.2.15 uid 0
cacheCompare metrics when you have multiple default routes — lower metric wins:
ip route showdefault via 10.0.2.2 dev enp0s3 proto dhcp src 10.0.2.15 metric 116
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.15 metric 116
192.168.56.0/24 dev enp0s8 proto kernel scope link src 192.168.56.116 metric 117If bulk traffic should prefer the faster uplink but ip route get shows the wrong dev, fix policy routing or NetworkManager connection metrics — see ip route command and network is unreachable when paths fail entirely.
Determine network vs application bottleneck
Split where time is spent. curl can print phase timings so you see whether DNS, TCP connect, or the server response dominates:
curl -o /dev/null -s -w "namelookup: %{time_namelookup}s connect: %{time_connect}s starttransfer: %{time_starttransfer}s total: %{time_total}s speed: %{speed_download} B/s\n" http://speedtest.tele2.net/1MB.zipnamelookup: 0.047471s connect: 0.050023s starttransfer: 2.927185s total: 3.344723s speed: 313501 B/sconnect near 50 ms with starttransfer near 3 s means TCP came up quickly but the server took seconds before sending bytes — application or remote congestion, not a local duplex mismatch. Compare against raw TCP on the same path:
iperf3 -c 127.0.0.1 -t 3 -f mWhen iperf3 shows high megabits per second but one curl URL stays slow, test another mirror or run port connectivity checks on the service port. When iperf3 and curl are both slow with low ethtool speed or rising interface drops, fix the link and routes first.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
ethtool shows 100 Mb/s on a gigabit link |
Bad cable, port, or autoneg | Reseat cable; try another switch port; force speed only as a temporary test |
High TX dropped during transfers |
Qdisc or ring buffer pressure | Check fq_codel drops; tune NIC ring buffers per vendor docs; reduce parallel streams |
Fast ping, slow downloads, high time_starttransfer |
Remote server or TLS overhead | Try another URL; test same host with iperf3; profile application |
| Slow only through VPN/tunnel | Tunnel MTU too high | Lower tunnel MTU; enable MSS clamp; test with ping -M do -s stepping down |
iperf3 fast LAN, slow internet |
WAN bandwidth cap or ISP shaping | Test at different times; compare gateway ping vs remote; expect lower WAN bitrate |
| Traffic exits wrong interface | Route metric or policy | ip route get DST; adjust NM metrics or add policy rules |
iperf3: error - unable to connect |
Server not running or firewall | Start iperf3 -s on peer; open TCP 5201 in firewall |
References
- iperf3(1) — Linux manual page
- curl(1) — Linux manual page
- ethtool(8) — Linux manual page
- ip(8) — Linux manual page
- ping(8) — Linux manual page
Summary
Slow network complaints on Linux need a number before a fix — curl with speed_download gives a quick HTTP throughput baseline, and iperf3 between two hosts measures raw TCP when you need to exclude a single web server from the test. Pair those results with ping and mtr on the same path so latency and loss do not undermine an otherwise fast link.
Local link problems show up in ethtool (Speed, Duplex, Link detected) and in ip -s link error and drop counters. MTU mismatches punish large transfers while small probes still work — exercise ping -M do -s 1472 on standard Ethernet. ip route get confirms bulk traffic leaves the interface you expect; wrong metrics send packets through a slower uplink.
When curl phase timings show long time_starttransfer but fast connect, suspect the remote endpoint or congestion far from your NIC. When iperf3 and curl are both slow and the link negotiated below gigabit or drops are climbing, fix hardware and routing before you tune application buffers. For sustained loss on the path, continue with Linux packet loss troubleshooting.

