Linux servers connected by Ethernet cables in a clean data center, realistic network performance testing
Networking Tutorials
William  

A Practical Iperf3 Method for Linux Server Speed Tests

Use iperf3 with one Linux server listening and the other acting as the client. Start with a controlled TCP run, then test the reverse direction, parallel streams, longer duration, and competing traffic. Check CPU use, socket statistics, interface counters, and kernel logs beside the bandwidth line. A plausible number is not a diagnosis if you don't know what limited it.

This is the practical way to learn how to test network speed between Linux servers with iperf3. The tool measures traffic between two hosts. It does not tell you whether the limit came from the link, a route, a firewall, a receive window, a busy CPU, or a failing network interface.

Install and verify iperf3 before testing

Install iperf3 on both Linux servers, then confirm the binary each host will run.

iperf3 --version

That output tells you the command exists. It does not prove that the hosts can reach each other or that they will use the intended interface.

Find the addresses and interfaces before you start the test.

ip -br addr
ip route get <SERVER_IP>

ip -br addr shows the addresses assigned to each interface. ip route get shows which local address and interface Linux will use for the destination. On a multi-homed server, this catches the common mistake of testing the management network instead of the storage or private network.

Check basic reachability from the client.

ping -c <COUNT> <SERVER_IP>

A failed ping may mean a firewall rule, missing route, or disabled Internet Control Message Protocol (ICMP) response. It does not prove the TCP test will fail. Conversely, a successful ping says little about sustained throughput.

Allow the chosen TCP port through host firewalls and network firewalls. If the firewall blocks the port, iperf3 will fail before it measures anything. Check the listening server output and use ss on the server:

ss -ltnp

The output should show an iperf3 process listening on the address and port you selected. If it listens only on a loopback address, remote clients won't reach it. Linux networking enjoys making the wrong address look perfectly healthy.

Start the iperf3 server on Linux

Run the server in listening mode and leave its terminal visible during the first test.

iperf3 -s -p <PORT>

The -s flag starts server mode. The -p flag selects the TCP port. Choose a port allowed by every firewall between the hosts.

If the server has several addresses, bind the listener to the intended one.

iperf3 -s -B <SERVER_IP> -p <PORT>

-B binds the process to one local address. This prevents the test from quietly using the wrong interface. Check the startup output for bind errors before you move to the client.

For a longer investigation, run the server under systemd-run or inside a terminal multiplexer so its output stays available. Do not hide the first server run in the background. The listener reports connection failures and startup problems that you will need later.

You can also inspect the socket after starting it:

ss -ltnp | grep iperf3

If this shows no listener, the client cannot succeed. If it shows the wrong local address, fix the bind or routing decision before changing test flags.

The official iperf3 documentation describes the full option set. Read it when you move beyond basic TCP tests. Copying a tuning command without knowing which layer it changes is how a clean test becomes folklore.

How do you test network speed between Linux servers with iperf3?

Two Linux servers connected directly by Ethernet cables for controlled throughput testing

Start the client from the other Linux server and target the listening server.

iperf3 -c <SERVER_IP> -p <PORT> -t <SECONDS>

The -c flag makes this host the client. Traffic flows from the client to the server by default. -t sets the test duration, which gives you a repeatable baseline instead of relying on a short burst.

Use the same source and destination hosts for your first few runs. Keep the selected interface, port, and duration unchanged. Record the complete output, including retransmissions and congestion-window information when iperf3 prints it.

A hostname works too:

iperf3 -c <SERVER_NAME> -p <PORT> -t <SECONDS>

However, use the literal server address for the first baseline. That removes name resolution from the test. Once the address-based run works, compare it with the hostname command to expose DNS or address-selection problems.

A complete answer to how to test network speed between Linux servers is: run iperf3 -s on one host, run iperf3 -c <SERVER_IP> on the other, and compare repeated TCP results while checking the host and interface counters.

Set reporting intervals and test duration

Use -i to print progress during the test and -t to control how long the test runs.

iperf3 -c <SERVER_IP> -p <PORT> -t <SECONDS> -i <INTERVAL>

The interval output shows whether throughput is steady. A single final average can hide a link that starts fast, collapses under load, and recovers before the test ends.

Use a shorter run to check that the connection and route work. Use a longer run when you need to expose queue growth, retransmissions, thermal throttling, or a host that runs out of receive buffers under sustained traffic.

The interval is not a sampling instrument for every packet. It is a report of traffic observed during each reporting period. Treat a sudden drop as a clue, then match its time with sar, ss, journalctl, and interface counters.

Save machine-readable output when you need to compare runs:

iperf3 -c <SERVER_IP> -p <PORT> -t <SECONDS> -i <INTERVAL> -J > iperf3-run.json

The -J flag writes JSON output. Keep the command line beside the file. A result without its direction, stream count, duration, and route is only a number with paperwork around it.

Use IP addresses before hostnames

Use a literal IP address when you are isolating network performance. Use a hostname after that path works and you want to test the name-resolution and address-selection path separately.

Check what the hostname resolves to:

getent ahosts <SERVER_NAME>

This output shows the addresses returned through the system name service. A hostname may resolve to an address on a different network, an IPv6 address, or an interface you did not intend to test.

For a multi-homed server, pair the client target with a route check:

ip route get <RESOLVED_SERVER_IP>

If the route selects the wrong interface, fix the route or target the correct address. Do not add more streams to compensate for a test that never used the intended link.

Binding the server with -B controls where it listens. It does not force the client to use a matching source address. Verify both sides with ip route get and, if needed, bind the client to a local address with -B:

iperf3 -c <SERVER_IP> -B <CLIENT_IP> -p <PORT> -t <SECONDS>

Interpret transfer, bandwidth, and retransmissions

Administrator inspecting Ethernet connections between Linux test servers inside a server rack

Read Transfer and Bandwidth as different values. Transfer is the amount of data moved during the test. Bandwidth is the average rate over the reported period.

Network link capacity is usually stated in bits per second. iperf3 reports bandwidth in a readable unit, but you still need to compare the result with the actual link, route, and host limits. Do not compare a raw byte count with a link rate and call the result slow.

Look at each interval before trusting the final average:

  • Flat intervals suggest a stable path or a stable limit. That is useful, but it does not identify which one.
  • A high first interval followed by a lower rate suggests startup burst, queueing, shaping, or host pressure. Check the timing before changing flags.
  • Large swings can point to congestion, power management, a busy virtual host, or competing traffic. Match them against CPU and interface counters.
  • A low rate with no retransmissions often points to CPU, socket-window, route, or interface limits. Do not blame packet loss without packet-loss evidence.
  • Retransmissions during a TCP run mean data had to be sent again. Check congestion, packet loss, errors, and duplex behavior before changing buffer settings.

For TCP tests, iperf3 may show retransmission counts and congestion-window details. A rising retransmission count is evidence that the sender is not delivering cleanly. It is not a command-line tuning invitation.

Inspect the socket while a test runs:

ss -tin

This shows TCP state, negotiated options, congestion information, and socket details. Compare the client and server output. A small or changing congestion window can explain a low result even when the interface itself reports little traffic.

Test one-way performance in both directions

The default test sends traffic from the client to the server.

iperf3 -c <SERVER_IP> -p <PORT> -t <SECONDS> -i <INTERVAL>

This tests one direction only. Run the reverse direction with -R:

iperf3 -c <SERVER_IP> -p <PORT> -t <SECONDS> -i <INTERVAL> -R

With -R, the server sends data back to the client after the client establishes the control connection. Keep the server output visible so you can see which side is serving the traffic.

Run both directions separately. Asymmetric results can expose a bad route, traffic shaping, a duplex problem, receive-side CPU pressure, or a damaged interface. The reverse test is not an optional extra when the network is suspected. It is one of the fastest ways to split the problem.

Check interface counters before and after each run:

ip -s link show dev <INTERFACE>

Look for dropped packets, errors, and unusual increases on the interface that carried the test. A low iperf3 result with rising NIC errors needs a cable, port, driver, or hardware investigation. More TCP streams won't repair it.

Test bidirectional traffic with –bidir

Use --bidir to send traffic in both directions during the same test.

iperf3 -c <SERVER_IP> -p <PORT> -t <SECONDS> -i <INTERVAL> --bidir

This creates opposing flows at the same time. It is different from running one client-to-server test and then a separate reverse test. Separate runs measure each direction without the other flow competing for queues, CPU, and link capacity.

Bidirectional testing is useful for links that carry traffic both ways, such as replication, storage access, and busy router uplinks. It can also expose a shared bottleneck that one-way tests hide.

Do not call the bidirectional result the pure capacity of either direction. The opposing flows compete by design. If both directions fall together, inspect the shared link, host CPU, queueing, and interface counters. If only one side collapses, inspect that direction's route and receive path.

Add parallel streams only after the baseline

Start with one TCP stream. Add parallel streams only after the single-stream result is understood.

iperf3 -c <SERVER_IP> -p <PORT> -t <SECONDS> -i <INTERVAL> -P <STREAMS>

-P creates parallel client connections. More streams can fill a path that one TCP flow cannot fill because of latency, congestion control, or a narrow congestion window. They can also hide a single-flow problem and push a CPU-limited host harder.

Compare a single stream with a small, controlled set of parallel streams. Keep the duration and direction unchanged. Record the total bandwidth and each stream's behavior when the output provides it.

If one stream is poor but parallel streams approach link capacity, investigate latency, TCP window growth, and congestion control. If every stream is poor, look lower in the stack. The network may be fine and the host may be the limit.

Build a repeatable iperf3 test matrix

Use a test matrix. One successful command does not establish a network baseline.

  1. Confirm the intended addresses and route on both servers.
  2. Run a single-stream TCP test in the default direction.
  3. Repeat it with the same duration and interval.
  4. Run the reverse-direction test with -R.
  5. Compare a controlled parallel-stream run with -P.
  6. Run a simultaneous bidirectional test with --bidir.
  7. Repeat during competing traffic if the real workload shares the link.
  8. Record CPU state, interface counters, socket details, and kernel messages for every run.

Record the command line, hostname or address, local interface, direction, stream count, duration, interval, result, retransmissions, and system load. Keep the server and client clocks close enough that interval output can be matched with logs.

Check CPU usage on both machines while the test runs:

mpstat -P ALL <INTERVAL>

If mpstat is unavailable, use the system's normal CPU monitor. A saturated core can cap packet processing before the link reaches capacity. Virtual machines add another limit through the hypervisor, virtual Network Interface Controller (NIC), and host scheduling.

Test with and without competing traffic when that reflects the real system. A quiet-link result answers one question. A production-link result answers another. Mixing them produces a baseline nobody can reproduce.

Diagnose unexpectedly low iperf3 throughput

Linux home lab servers, router, and Ethernet cables arranged for troubleshooting network performance

Start by deciding which layer is failing. Do not change TCP buffers, congestion control, or offload settings because a search result listed them.

Check the route and interface first:

ip route get <SERVER_IP>
ip -br link
ip -s link show dev <INTERFACE>

These commands tell you whether Linux chose the intended path, whether the interface is up, and whether errors or drops increase during the run.

Check TCP retransmissions and socket state:

ss -tin
nstat -az TcpRetransSegs TcpExtTCPTimeouts

The exact counters vary by kernel and tooling. The useful part is the change during a controlled test. Compare a quiet baseline with a run that reproduces the problem.

Check the Maximum Transmission Unit (MTU) and route:

ip link show dev <INTERFACE>
ip route get <SERVER_IP>

An MTU mismatch can cause fragmentation, dropped packets, or a path that behaves differently from the local link. Test the actual path before forcing a new MTU across the system.

Inspect driver and NIC counters:

ethtool -S <INTERFACE>
ethtool <INTERFACE>

Look for receive errors, transmit errors, missed packets, pause frames, and link-state problems. Counter names differ by driver, so read the labels instead of assuming every NIC reports the same things.

Which logs and tools expose the real bottleneck?

Read kernel messages during the test:

dmesg -T | tail -50
journalctl -k --since "10 min ago"

These commands expose link flaps, driver resets, transmit queue failures, and other messages that iperf3 cannot see. The kernel ring buffer is often where the hardware complaint appears first.

Use strace for process-level questions, not as a pretend packet analyzer:

strace -f -tt -e trace=network iperf3 -c <SERVER_IP> -p <PORT> -t <SECONDS>

This shows socket calls, connection setup, address errors, and timing around network-related system calls. It will not explain every packet lost by a switch. For packet-level work, use a focused tcpdump workflow and capture only the relevant interface and host pair.

If the problem follows a VPN, tunnel, or overlay, test the underlying interface separately. A tunnel adds encryption, headers, routing, and often a smaller effective MTU. The WireGuard Linux server setup guide covers the configuration side, but iperf3 still needs a physical-path baseline before you blame the tunnel.

The real problem is usually visible in the route, the socket, the host CPU, or the interface counters. Check those before reaching for unexplained tuning flags.

FAQ

Can iperf3 measure Internet speed between Linux servers?

Yes, but only for the path between those two endpoints during that run. Provider shaping, congestion, routing changes, and host load all become part of the result. Treat it as a path measurement, not a permanent score for either server.

Does iperf3 test disk speed?

No. The program moves generated data through the network socket and reports that transfer. Disk activity matters only if another job is consuming the CPU, memory, or network resources needed by the test.

Should you test UDP instead of TCP?

Use UDP when the question involves packet loss, jitter, or a chosen sending rate. For normal server traffic, begin with TCP because that shows what a reliable application flow can sustain. A UDP result can exceed what the path or application can handle and still look impressive.

Can a firewall allow ping but block iperf3?

Yes. Ping sends ICMP, while iperf3 needs the selected TCP or UDP port. Check the actual listener and port from the server rather than treating a ping reply as a firewall test.

Why does a reverse test differ from the normal test?

The tests send data through opposite paths, and those paths can have different shaping, routes, receive load, or interface errors. Compare both hosts' route output and counters before calling either result wrong. The difference is evidence about direction, not a measurement failure.

Related on this blog