Guides

Test a VPS's network: speedtest, iperf3 and mtr — and read the results honestly

Measure a server's bandwidth with speedtest and iperf3, find packet loss with mtr, and see why one test to one server says little about your users' route.

Published ~11 min read

To measure a server’s throughput, run iperf3 between two machines you control: iperf3 -s on one, iperf3 -c IP -P 4 on the other, and the same again with -R for the opposite direction. For a quick look at the server’s internet connection, use Ookla’s speedtest CLI. To check the quality of the path (packet loss, latency and where it goes wrong), run mtr -rwbzc 100 target from both ends. Each test measures one route to one machine at one moment, which is not necessarily what your users get.

the short version
# throughput between two machines you control (TCP port 5201)
iperf3 -s                                  # on the server
iperf3 -c 203.0.113.10 -P 4 -t 30          # on the other machine: it sends to the server
iperf3 -c 203.0.113.10 -P 4 -t 30 -R       # reverse: the server sends

# quick internet test with Ookla's CLI (install below)
./speedtest

# path quality: 100 probes per hop, as a report
mtr -rwbzc 100 203.0.113.10

What does each tool measure?

  • speedtest: download, upload and latency between your server and one Speedtest server, usually a nearby, well-connected one. That is a good check of the server’s own connection, but a poor proxy for users far away.
  • iperf3: raw TCP or UDP throughput between two endpoints you choose, with no web server, disk or browser involved. It is the cleanest test of a specific route.
  • mtr: latency and packet loss at every hop along the path, measured continuously. It shows no throughput, but it shows where things go wrong.
  • traceroute / tracepath: the path, taken once. Useful, but a single pass says little about loss.

For what a visitor actually experiences (DNS, TCP, TLS and time to first byte), time a real request with curl as described in Frankfurt vs Amsterdam.

How do I run speedtest from the command line?

Ookla, the company behind speedtest.net, publishes an official CLI. Its static Linux build runs on any distribution without adding a repository:

Ookla speedtest CLI · x86_64
curl -fsSLO https://install.speedtest.net/app/cli/ookla-speedtest-1.2.0-linux-x86_64.tgz
tar -xzf ookla-speedtest-1.2.0-linux-x86_64.tgz speedtest
./speedtest --accept-license --accept-gdpr   # first run: accept the licence and privacy terms

./speedtest -L                 # nearby servers with their IDs
./speedtest -s 12345           # test against one specific server
./speedtest -f json-pretty     # machine-readable output (speeds in bytes per second)

1.2.0 was the current version when this was written. speedtest.net/apps/cli lists newer builds, an ARM build (aarch64) and the apt and dnf repositories. On new distribution releases the repository setup does not always work right away, which is why the tarball is the safer default here.

The speedtest-cli package in Debian and Ubuntu is a different program: a Python client written by a third party. It talks to the same servers and also installs a command called speedtest, but on fast links it can report lower numbers than the official client. If speedtest --version does not mention Ookla, you are running that one; sudo apt remove speedtest-cli removes it.

Run the test against two or three different servers from the -L list. If the result changes a lot, the test server was the limit, not yours. Speeds are in megabits per second; divide by 8 for megabytes.

How do I use iperf3?

iperf3 needs a second machine: another VPS, a server at the office, or your own computer if you want to test the route to your desk. Install it on both ends:

install
sudo apt install -y iperf3     # Debian, Ubuntu
sudo dnf install -y iperf3     # Rocky, AlmaLinux, CentOS Stream

Debian and Ubuntu ask whether to start iperf3 as a daemon automatically. Answer No: you only want it running during a test. Open port 5201 for the duration of the test only, and only for the other machine’s IP:

on the server
sudo ufw allow from 198.51.100.7 to any port 5201   # TCP and UDP, one source IP
iperf3 -s -1                                         # answer one test, then exit

# when you are done
sudo ufw delete allow from 198.51.100.7 to any port 5201
on the other machine
iperf3 -c 203.0.113.10 -t 30              # one TCP stream, this machine → server
iperf3 -c 203.0.113.10 -t 30 -P 4         # four parallel streams
iperf3 -c 203.0.113.10 -t 30 -P 4 -R      # reverse: server → this machine
iperf3 -c 203.0.113.10 -t 30 --bidir      # both directions at once (iperf3 3.7 or newer)
iperf3 -c 203.0.113.10 -t 30 -u -b 200M   # UDP at a fixed 200 Mbit/s

iperf3 -s -1 serves a single client and exits, so you have to start it again before each test. Leave out -1 to keep it running until you press Ctrl+C.

Reading the result

  • sender and receiver lines. At the end, iperf3 prints a total for each side. The receiver figure is what actually arrived. With -P, read the [SUM] lines.
  • Retr is the number of TCP retransmissions. A few are normal. Many, together with a speed that keeps dropping, point to loss or congestion on the path.
  • One stream or four. A single TCP stream over a long path is limited by latency and by any loss, so -P 1 shows what one download gets and -P 4 shows what the link carries. Both are real numbers; say which one you are quoting.
  • Direction. Without -R the client sends. To measure what your users get when they download from the server, run -R from a machine near them.
  • UDP. TCP adapts its speed, UDP does not. With -u -b you set the rate and read Jitter and Lost/Total Datagrams, which is what matters for games and VoIP. Without -b, a UDP test sends only 1 Mbit/s.

Before version 3.16, iperf3 handled every stream in one thread, so at multi-gigabit rates a single CPU core can be the limit. Debian 12 ships 3.12, while Ubuntu 24.04 and Debian 13 ship newer, multi-threaded versions; iperf3 --version tells you which one you have. Public iperf3 servers exist, but they are often busy or far away. A machine you control, close to your users, gives numbers you can trust.

How do I read an mtr report?

install and run
sudo apt install -y mtr-tiny   # Debian, Ubuntu (text-only package)
sudo dnf install -y mtr        # Rocky, AlmaLinux, CentOS Stream

mtr -rwbzc 100 203.0.113.10
#   -r report   -w wide (full hostnames)   -b names and IPs
#   -z AS numbers   -c 100 probes per hop (takes about 100 seconds)

Here is an example report. The addresses and numbers are illustrative, but the pattern is common:

example report
Start: 2026-11-15T09:14:02+0000
HOST: laptop                       Loss%   Snt   Last   Avg  Best  Wrst StDev
  1. AS???    192.168.1.1           0.0%   100    1.1   1.3   0.9   4.2   0.4
  2. AS64496  198.51.100.1          0.0%   100    8.4   8.9   7.8  15.1   1.1
  3. AS64496  198.51.100.45        42.0%   100   10.2  11.0   9.6  19.8   1.9
  4. AS64500  192.0.2.17            0.0%   100   14.6  14.9  14.1  21.3   0.9
  5. AS???    ???                 100.0%   100    0.0   0.0   0.0   0.0   0.0
  6. AS64511  203.0.113.10          0.0%   100   15.2  15.4  14.8  18.0   0.6
  • Loss%: the share of probes that got no reply from that hop. Snt: probes sent.
  • Last, Avg, Best, Wrst: round-trip times in milliseconds: the most recent, the average, the fastest and the slowest.
  • StDev: how much the times vary. A high value at the final hop means jitter.

The rule that matters: only loss that continues to the last hop is real. Hop 3 above “loses” 42%, yet hops 4 and 6 lose nothing. That router simply answers a limited number of probes addressed to itself and still forwards your traffic normally. Hop 5 never answers at all, which is just as harmless. If the loss started at hop 3 and the last line showed loss too, the problem would be real, and it would start at or just before hop 3. The same goes for latency: a jump that persists to the end is real distance or congestion, while a spike at one hop only is a router that is slow to reply.

Routes are often asymmetric: the path back from the server can take different networks than the path to it. Run mtr in both directions. If a network filters ICMP, probe the port you actually serve: mtr -rwbzc 100 -T -P 443 203.0.113.10.

traceroute, tracepath and mtr: what’s the difference?

  • traceroute sends three probes per hop, once. On Linux it uses UDP by default; -I switches to ICMP, and sudo traceroute -T -p 443 host uses TCP, which gets through more firewalls. Package: traceroute.
  • tracepath needs no root and also reports the path MTU, which helps when large packets disappear on a VPN or tunnel. Package: iputils-tracepath on Debian and Ubuntu.
  • mtr repeats the probes continuously and collects statistics. Use it for anything you plan to send to someone else.

How do I test the network from Windows?

cmd or PowerShell
tracert -d 203.0.113.10                      # the path, without name lookups
pathping -n 203.0.113.10                     # path plus loss per hop (takes several minutes)
Test-NetConnection 203.0.113.10 -Port 443    # PowerShell: is this TCP port reachable?
Test-NetConnection 203.0.113.10 -TraceRoute  # PowerShell: a quick traceroute

pathping is the closest thing Windows has to mtr. It sends 100 probes to each hop, which is why it is slow. Ookla’s CLI is also available as a Windows build. iperf3 is not officially supported on Windows, but community builds exist; use the same or a similar version on both ends. On a Windows VPS, open the port in the firewall only for the test, as shown in opening a port in Windows Firewall.

Why is my result lower than the plan’s port speed?

The port speed listed with a plan is a ceiling. On VMHeaven’s KVM plans it ranges from 200 Mbit/s on the smallest plans to 10 Gbit/s on the largest, under fair use. A test only reaches it if everything else on the path keeps up:

  • The far end. The speedtest server or iperf3 peer has its own port, its own load and its own limits. Home connections usually upload far more slowly than they download.
  • The route. TCP throughput falls with distance and with every lost packet, so a single stream across a continent gets much less than four streams across town.
  • CPU. At high rates one core can become the limit: old iperf3 versions, the Python speedtest client, or a single-threaded TLS download. Watch top during the test. If one core sits at 100%, or si (softirq) is high, you are measuring the CPU, not the network.
  • Units and disks. Mbit/s is not MB/s: 1 Gbit/s is at most 125 MB/s, and a little less after protocol overhead. If you test by downloading a file to disk, you may be measuring the disk. Send it to /dev/null instead, or see how to test disk speed.

Which location will be faster for my users?

That depends on the route from their networks, not on any one benchmark. Measure from where your users are: a cheap machine in their region running iperf3 and mtr against each candidate, RIPE Atlas probes, or a transit provider’s looking glass. For European audiences, Amsterdam and Frankfurt are close enough that the route and the legal setting usually matter more than distance. The trade-offs are covered in Frankfurt vs Amsterdam, and the location pages for Germany and the Netherlands list the plans available in Frankfurt and Amsterdam. Both VMHeaven locations run on a redundant premium carrier blend with always-on DDoS protection (how that works is in DDoS-protected VPS), on every line. Still, measure from where your users are rather than trusting anyone’s map.

For our Amsterdam network you can start in the browser: the looking glass runs ping, traceroute and MTR from Amsterdam back to you.

What should I send to support?

A network report that support can act on contains mtr in both directions, taken while the problem is happening, with the time attached. mtr prints a Start: timestamp in report mode; give the time zone as well.

collect it
# on your computer → the server
mtr -rwbzc 100 203.0.113.10 > mtr-to-server.txt

# on the server → your public IP (inside SSH: the first field of echo $SSH_CLIENT)
mtr -rwbzc 100 198.51.100.7 > mtr-from-server.txt

# if it is about throughput: iperf3 in both directions
iperf3 -c 203.0.113.10 -t 30 -P 4    > iperf-up.txt
iperf3 -c 203.0.113.10 -t 30 -P 4 -R > iperf-down.txt

Add three facts: the server’s IP, your own public IP, and what exactly is slow (downloads from the server, uploads to it, one country or everyone) and since when. If it only happens at certain hours, run the same commands at a good time and at a bad one. A single ping or a phone speedtest over Wi-Fi does not help anyone. If SSH itself keeps dropping while you test, read SSH broken pipe first.

Frequently asked

Why is speedtest slower than my server's port speed?

The port speed is a ceiling, not a promise for every route. The result also depends on the test server's own capacity and load, the distance and any packet loss on the path, and the CPU: one busy core, an old iperf3 or the Python speedtest-cli client can cap the number. Test against two or three different servers, use iperf3 with -P 4 to a machine you control, and watch top during the test.

How much packet loss in mtr is normal?

Judge the last line, the destination. 0% there is normal. Loss shown at a hop in the middle that does not continue to the last hop is a router rate-limiting replies to probes and does not affect your traffic. Loss that starts at one hop and persists to the destination over several 100-probe runs is real, and even 1–2% of it is noticeable in games, voice calls and TCP throughput.

Should I use iperf3 or speedtest?

Use both, because they answer different questions. speedtest checks the server's connection to a nearby Speedtest server and needs nothing on the other end. iperf3 measures one specific route between two machines you control, in either direction, with TCP or UDP, which makes it the right tool for how fast the server is to your office or to your users' region. For loss and latency along the path, add mtr.

How do I send a useful network report to support?

Run 'mtr -rwbzc 100' from your computer to the server and from the server back to your public IP while the problem is happening, and save both reports. They include a timestamp; add your time zone. Include both IP addresses, what exactly is slow (downloads, uploads, one region) and since when, and for throughput problems iperf3 output with and without -R. A single ping or a phone speedtest is not enough to act on.

Related articles

All guides