mt76 rate control: why a client gets pinned at MCS0 (and how to prove it)
2026-10-11 · 3 min read
If an OpenWrt + mt76 AP sends to one client at MCS0 while every other client is fine, you are not imagining it —
and it is usually not a signal problem. This is the measured investigation.
1. Read the right counters first
iw dev <ap> station dump | grep -E "Station|tx bitrate|rx bitrate|tx failed|tx retries|expected"
| Field | Meaning | Trap |
|---|---|---|
tx bitrate |
last rate used AP to client | it is a sample, not an average — sample it repeatedly |
rx bitrate |
last rate client to AP | usually healthy even when downlink collapses |
tx failed / tx retries |
link-layer outcomes | compare against bytes moved, not frames alone |
Also confirm the direction with a cheap LAN transfer and count bytes on both ends (see section 3). If the AP sends far more bytes than the client receives, you have retransmission storms; if it sends roughly the same, the airtime is simply idle.
2. Where mt76 rate control lives
cat /sys/kernel/debug/ieee80211/phy*/rate_ctrl_alg # -> hw/driver
cat /sys/kernel/debug/ieee80211/phy*/hwflags # -> HAS_RATE_CONTROL
hw/driver plus HAS_RATE_CONTROL means the firmware/SoC picks the rate — mac80211's software rate control (minstrel)
is not in charge. So "just switch the rate algorithm" is not an option; you influence it indirectly.
Two debugfs knobs matter in practice:
cat /sys/kernel/debug/ieee80211/phy*/mt76/vow_atf # firmware airtime fairness, default 1
cat /sys/kernel/debug/ieee80211/phy*/mt76/aql_enable # airtime queue limit
3. The measurement that identified the bug
Same client, same minutes, only vow_atf changed (grade E — raw capture and the scripts that produced it are
published [1] [2]). Idle 60 s, then six 6-second LAN downloads:
vow_atf |
Results | Behaviour |
|---|---|---|
| 1 (default) | 9.5 / 7.3 / 9.5 / 7.4 / 9.6 / 7.2 Mbps | 36 s of continuous traffic never recovers |
| 0 | 7.8 / 8.8 / 20 / 146 / 387 / 393 Mbps | recovers within ~15 s |
| 0 + client reassociation | 369 / 374 / 376 / 390 / 409 / 397 Mbps | fast from the first burst |
Byte accounting during the collapsed state: 12 s of transfer gave 12.4 MB received vs 12.87 MB transmitted by the AP. So there was almost no retransmission waste — the rate was low and the channel mostly idle. That rules out a deaf client and points at rate selection.
4. What actually causes the collapse
Two independent triggers, both reproducible on MT7986 + mt76:
- Client idle/power-save behaviour: about 1 s of idle is enough for the AP transmit rate to fall to
MCS0 1SS. Withvow_atf=1it then stays there even under sustained load. - Narrow client in wide BSS: a 40 MHz-only client inside an 80 MHz BSS collapses periodically regardless of ATF. Native-width operation (40 MHz BSS) is stable at 380-420 Mbps.
5. What to do
# 1) disable the firmware feature that prevents recovery (and persist it)
echo 0 > /sys/kernel/debug/ieee80211/phy*/mt76/vow_atf
# 2) if the client is a 40 MHz-only device, match the radio width
sh /usr/bin/wifi-htmode HE40 # CSI resolution drops; clients stay usable
# 3) as a last resort, force a fresh association (resets the rate state)
iw dev <ap> station del <client-mac>
Persisting step 1 matters: the debugfs value is lost on driver reload. The project toolkit ships an init script and a
watchdog that re-apply it (scripts/mt76-wifi-tune, scripts/csi-watchdog.sh).
6. What not to conclude
- Do not trust a single
tx bitratesample (it is the last rate, not an average); - Do not blame the client without direction tests (upload was fine at 600 Mbps PHY, 188 Mbps measured);
- Do not test with a public mirror: broadband variation will masquerade as Wi-Fi behaviour.
Related: 80 MHz vs 40 MHz · OpenWrt Wi-Fi slow after idle · router CSI reproduction
References and data sources
Every external claim carries a source and an evidence grade (grading scheme). Grade E marks first-party, reproducible measurements from this project.
- Grade E · first-party measurement
This project's 10-minute raw capture (57,293 records / 600.0 s, SHA-256 00373f83…95e2)
Router CSI Lab · 2026
csi.okwujun.pw/zh/datasets/ · verified: Reassembled chunks verified byte-identical (2026-10-11) - Grade E · first-party measurement
Router CSI Toolkit — capture/analysis/watchdog scripts (MIT)
Router CSI Lab · 2026
csi.okwujun.pw/zh/tools/ · verified: Repository bundle has a SHA-256; scripts run on real hardware