mtr: Continuous Path Monitoring on Linux

Loss and latency per hop against a link with 12 percent loss injected on purpose, and the one rule that separates real loss from cosmetic loss.

Terminal showing an mtr report with 22 percent loss and 167 ms latency appearing at hop 3

A traceroute is a photograph. It tells you what the path looked like for the three seconds it ran, which is close to useless when the complaint is "it's slow sometimes" or "the call keeps dropping." Intermittent loss does not show up in a snapshot. mtr is the tool that fixes that: it runs traceroute and ping at the same time, forever, and gives you a per hop loss and latency table that updates live.

This article uses a lab link with deliberately injected impairment (80 ms of latency, 12 ms of jitter and 12 percent loss on one router to router hop) so the loss column has something real in it. Everything below is genuine output from a Debian 13 host through a Cisco Modeling Labs topology, before, during and after the impairment. It is part of the Linux networking commands cluster.

Start with a clean baseline

You cannot read an mtr report without knowing what healthy looks like on that path. Here is the four hop lab path with nothing wrong with it:

j@llmbits:~$ sudo mtr -rwnc 20 10.77.3.10
Start: 2026-08-18T22:14:53-0700
HOST: llmbits    Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 10.77.0.1   0.0%    20    3.1   3.1   2.8   3.5   0.2
  2.|-- 10.77.12.2  0.0%    20    3.7   4.0   3.7   4.6   0.3
  3.|-- 10.77.23.3  0.0%    20    4.9   4.9   4.2   5.6   0.3
  4.|-- 10.77.3.10  0.0%    20    5.3   5.4   4.1   7.4   0.6

Four flags do most of the work and they are worth committing to memory as one word:

-rReport mode. Run a fixed number of cycles, print a table, exit. This is what you paste into a ticket.
-wWide report. Stops long hostnames from being truncated into nonsense.
-nNo reverse DNS. Faster, and it removes a dependency that can itself be broken.
-c NCycles to run. Under 20 the loss percentages are too coarse to mean anything.

Without -r, mtr takes over the terminal and updates in place, which is the right mode when you are watching a problem happen. With -r it is a reporting tool, and that is how it usually ends up in an escalation.

What each column actually means

Loss% is the share of probes sent with that TTL that produced no reply. Read down the column, never across a single row.

Snt is probes sent to that hop, which should match your -c value.

Last, Avg, Best, Wrst are round trip times in milliseconds to that hop. Best is the most honest of the four, because it is the one measurement least polluted by a router being busy with something else.

StDev is the standard deviation of those round trips, which is jitter under another name. A low average with a high standard deviation is a worse experience for voice and video than a higher, steadier average.

Now with 80 ms of latency, 12 ms of jitter and 12 percent loss applied to the R2 to R3 link only:

j@llmbits:~$ sudo mtr -rwnc 50 10.77.3.10
Start: 2026-08-18T22:31:19-0700
HOST: llmbits    Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 10.77.0.1   0.0%    50    3.0   3.0   2.7   3.5   0.2
  2.|-- 10.77.12.2  0.0%    50    4.1   4.1   3.4   6.0   0.4
  3.|-- 10.77.23.3 22.0%    50  164.6 167.1 151.9 185.2  10.2
  4.|-- 10.77.3.10 20.0%    50  160.4 167.9 151.0 183.0   9.6

This is the pattern you are looking for and it says three things at once.

Loss is zero at hops 1 and 2, appears at hop 3, and continues at hop 4. Loss that starts at a hop and persists through every hop after it is real loss on the path. The impairment is on the link between hop 2 and hop 3, and every packet that has to cross that link is exposed to it, including the ones destined for hop 4.

Latency jumps from 4 ms to 165 ms at the same hop and stays there. Eighty milliseconds was applied to the link, and a round trip crosses it twice, so 160 ms of added round trip is exactly right. Latency, like loss, is cumulative down the column.

The standard deviation goes from 0.4 to 10.2 at hop 3 and stays around 10 at hop 4, which is the 12 ms of injected jitter showing up as a measurement.

The percentages at hops 3 and 4 are not identical (22 percent versus 20 percent) and they should not be. Each hop is measured with its own independent set of probes.

The kind of loss you should ignore

The single most common misreading of mtr is treating loss at one intermediate hop as a fault. Routers deprioritize generating ICMP replies about themselves, because that is control plane work, while forwarding your traffic is not. A hop can show 40 percent loss while forwarding every single packet perfectly.

Real loss
Appears at hop N and is still there at every hop after it, including the destination. Affects traffic. Escalate it.
Cosmetic loss
Appears at hop N and is gone by hop N+1. That router rate limits its own ICMP. Ignore it completely.
Loss only at the last hop
The destination itself is rate limiting or dropping. Check the host, not the network. Confirm with a TCP probe.

The rule is one sentence long: only the loss at the final hop describes what your traffic experienced. Everything above it is diagnostic detail about where that loss began.

Cross-check with ping

When the mtr report says something you are about to escalate, confirm it with a plain ping to the destination. It is a completely different code path and it either agrees or it does not:

j@llmbits:~$ ping -c 20 -q 10.77.3.10
PING 10.77.3.10 (10.77.3.10) 56(84) bytes of data.

--- 10.77.3.10 ping statistics ---
20 packets transmitted, 18 received, 10% packet loss, time 19082ms
rtt min/avg/max/mdev = 149.250/167.928/187.155/11.880 ms

Ten percent loss and 168 ms average, against mtr's 20 percent and 168 ms at the same hop. The latency agrees precisely. The loss figures differ because they are separate samples of a 12 percent random drop, which is exactly the sort of variance you should expect and exactly why you run more than 20 cycles before making a claim. For the full set of ping options behind that command, see the Linux ping options guide.

TCP mode hides loss, and that is informative

mtr can probe with TCP SYNs instead of ICMP, which gets through firewalls that drop everything else. On the same badly impaired link, the result is startling:

j@llmbits:~$ sudo mtr -rwnc 20 -T -P 5201 10.77.3.10
Start: 2026-08-18T22:37:16-0700
HOST: llmbits    Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 10.77.0.1   0.0%    20    3.4   3.1   2.5   3.7   0.3
  2.|-- 10.77.12.2  0.0%    20    4.7   4.4   3.8   5.0   0.3
  3.|-- 10.77.23.3  0.0%    20  188.8 320.1 143.4 2202. 497.3
  4.|-- 10.77.3.10  0.0%    20  168.3 369.8 146.0 2205. 533.7

Zero percent loss on a link dropping 12 percent of packets. Look at the Wrst column instead: 2202 milliseconds, against a best of 143. TCP retransmitted the lost probes and eventually got answers, so from mtr's point of view nothing was lost. The loss did not disappear, it turned into latency and a standard deviation of 497.

That transformation is the single most useful thing to understand about loss on a TCP path, and it is why users report "slow" rather than "broken" when a link starts dropping packets. Use ICMP or UDP mode to measure loss. Use TCP mode to prove reachability through a firewall, and read its Wrst and StDev columns rather than its loss column.

The other half of the lab has no impairment, and tracing to a destination that avoids the bad link proves where the problem is not:

j@llmbits:~$ sudo mtr -rwnc 20 10.77.2.10
Start: 2026-08-18T22:37:41-0700
HOST: llmbits    Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 10.77.0.1   0.0%    20    3.0   3.1   2.9   3.4   0.1
  2.|-- 10.77.12.2  0.0%    20    4.3   4.2   3.3   6.1   0.5
  3.|-- 10.77.2.10  0.0%    20    5.0   4.5   4.1   5.0   0.2

Same first two hops, same routers, clean. The destination behind R2 is fine, the destination behind R3 is not, and the only difference between the two paths is the R2 to R3 link. That is the whole method: find a target on each side of the suspect link and compare. It converts "the network is slow" into a link name.

Probe size matters

-s sets the payload size. Small probes can sail through a link that mangles large ones, so if users report that logins work but file transfers hang, test with a big probe:

j@llmbits:~$ sudo mtr -rwnc 20 -s 1400 10.77.3.10
Start: 2026-08-18T22:38:51-0700
HOST: llmbits    Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 10.77.0.1   0.0%    20    3.4   3.4   2.8   3.9   0.3
  2.|-- 10.77.12.2  0.0%    20    4.7   4.6   4.1   5.6   0.3
  3.|-- 10.77.23.3 15.0%    20  146.2 166.5 146.2 177.5   7.8
  4.|-- 10.77.3.10 20.0%    20  175.7 170.5 148.3 190.3  11.4

Here the impairment is size independent, so 1400 byte probes lose at the same rate as 64 byte ones. When they do not (small probes clean, large probes lost) you are looking at an MTU problem rather than a loss problem, and tracepath is the tool that names it.

Machine readable output

mtr can emit CSV and JSON, which makes it trivial to schedule and graph:

j@llmbits:~$ sudo mtr -rwnc 20 --csv 10.77.3.10
Mtr_Version,Start_Time,Status,Host,Hop,Ip,Loss%,Snt, ,Last,Avg,Best,Wrst,StDev,
MTR.0.95,1787117910,OK,10.77.3.10,1,10.77.0.1,0.00,20,0,3.04,2.94,2.60,3.29,0.22
MTR.0.95,1787117910,OK,10.77.3.10,2,10.77.12.2,0.00,20,0,4.07,4.08,3.50,4.44,0.21
MTR.0.95,1787117910,OK,10.77.3.10,3,10.77.23.3,30.00,20,6,158.69,158.91,145.77,186.29,9.26
MTR.0.95,1787117910,OK,10.77.3.10,4,10.77.3.10,25.00,20,5,179.83,168.91,154.45,188.41,10.44

The unnamed ninth column is the raw drop count, which is more useful than the percentage when you are aggregating runs. --json gives the same data with field names, and is the better choice if something downstream is parsing it:

j@llmbits:~$ sudo mtr -rnc 20 --json 10.77.3.10
{
    "report": {
        "mtr": {
            "src": "llmbits",
            "dst": "10.77.3.10",
            "tos": 0,
            "tests": 20,
            "psize": "64",
            "bitpattern": "0x00"
        },
        "hubs": [
            {
                "count": 1,
                "host": "10.77.0.1",
                "Loss%": 0.0,
                "Snt": 20,
                "Last": 3.273,
                "Avg": 3.061,
                "Best": 2.615,
                "Wrst": 3.47,
                "StDev": 0.202
            },
[...]

A cron job running mtr -rnc 60 --json every ten minutes into a file, keyed by timestamp, will tell you more about an intermittent problem in a day than any amount of interactive troubleshooting. Intermittent faults are found by data you already collected, not by being at the keyboard at the right moment.

Proving it is fixed

With the impairment removed, the same command on the same path:

j@llmbits:~$ sudo mtr -rwnc 20 10.77.3.10
Start: 2026-08-18T22:39:39-0700
HOST: llmbits    Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 10.77.0.1   0.0%    20    2.7   3.0   2.6   3.3   0.2
  2.|-- 10.77.12.2  0.0%    20    5.4   4.2   3.5   5.4   0.4
  3.|-- 10.77.23.3  0.0%    20    5.0   5.1   4.8   6.3   0.3
  4.|-- 10.77.3.10  0.0%    20    5.3   5.5   5.1   6.1   0.2

Back to single digit milliseconds and zero loss on all four hops. Capture the before and the after with the same flag set and the same cycle count, or the comparison is worthless.

FAQ

Does mtr need root?

For raw ICMP probes yes, unless the binary carries cap_net_raw. mtr can fall back to unprivileged UDP mode, but ICMP mode is the one you want for loss measurement, so run it under sudo and stop thinking about it.

When should I use mtr instead of traceroute?

Use traceroute when the question is "what is the path" and you need control over the probe type. Use mtr when the question is "is the path healthy" or when the complaint contains the word "sometimes." mtr's per hop statistics over hundreds of probes are what make intermittent faults visible.

Why does hop latency sometimes go down as I move along the path?

Because you are measuring round trips to different routers over potentially different return paths, and because the replies are generated at different priorities. A hop that shows 200 ms followed by a hop that shows 20 ms just means the first router was slow to answer about itself. Only a rise that sustains through the remaining hops means anything.

How many cycles should I run?

At least 50 before you make a claim about loss, and several hundred if you are chasing something intermittent. With 10 cycles a single dropped probe reads as 10 percent loss, which is enough to send somebody down the wrong path for an afternoon.

Every hop past the firewall shows 100 percent loss. Is the path down?

Probably not. Try -T -P 443 or whatever port the service uses. If the TCP probe completes to the destination, the path is fine and the firewall is simply dropping ICMP, which is a configuration choice rather than a fault.

Key takeaways

  • mtr -rwnc 50 <target> is the command to memorize. Report mode, wide, numeric, 50 cycles.
  • Read the Loss% column downward. Loss that persists to the final hop is real; loss that clears on the next hop is ICMP rate limiting and means nothing.
  • Only the final hop's loss describes what your traffic experienced.
  • Latency and loss are both cumulative down the column. A rise that sustains marks the link where the problem starts.
  • StDev is jitter. A modest average with a large standard deviation is worse for real time traffic than a higher steady average.
  • TCP mode reports near zero loss on a lossy path because retransmits hide it. Read Wrst and StDev there instead, and use ICMP mode to measure loss.
  • Compare a target on each side of a suspect link to convert "slow network" into a specific link.
  • --json or --csv on a schedule finds intermittent faults that no interactive session ever will.

To understand the probe types mtr inherits, read traceroute in UDP, ICMP and TCP modes first. If large packets are the problem rather than lost ones, go to tracepath and path MTU discovery. For measuring what a healthy path can actually carry, the iPerf cluster takes over, and everything in this series is indexed on the Linux networking commands guide.

Read next