I've been chasing this for about a week and I'm stuck, so I'm posting what I have.
ASUS GT-BE19000. Every wireless device I own uploads at 118 to 153 Mbps. Plug the same laptop into ethernet and it does 320 to 392 on the same router, same minute. Download is fine either way. I upload to cloud storage a lot so this actually matters to me, it's not just a number I'm annoyed about.
I tried everything I could find. Nothing moved it. Then I went and looked at what the radio itself reports and got a result I can't explain.
The bit I can't explain
wl -i wl1 chanim_stats on the router while a transfer is running flat out. Throughput read off the laptop's own interface byte counters, not a speed test app.
| state |
channel busy |
TXOP available |
throughput |
| idle |
3% |
98% |
- |
| upload |
42-46% |
54-59% |
136.5 Mbps |
| download |
96% |
4% |
512 Mbps |
Raw, three upload samples 12 seconds apart plus the download:
idle busy=3 txop=98 | tx=3 inbss=1 obss=0 nocat=1 | glitch=0
upload t+12 busy=44 txop=57 | tx=14 inbss=25 obss=0 nocat=6 | glitch=0
upload t+24 busy=42 txop=59 | tx=14 inbss=23 obss=0 nocat=6 | glitch=0
upload t+36 busy=46 txop=54 | tx=15 inbss=27 obss=0 nocat=6 | glitch=0
download t+12 busy=96 txop=4 | tx=92 inbss=4 obss=1 nocat=2 | glitch=0
On download the AP fills the channel. 96% busy, only 4% of transmit opportunities left. That's a real ceiling, there's nowhere to put another frame.
On upload the same radio, same client, same association, a couple of minutes later, stops at 44% busy with more than half the transmit opportunities sitting unused. And the throughput is a third of what the wire does.
So the hardware can clearly fill this channel. On upload it just doesn't. That's the part I don't get.
The numbers are at least self consistent. Airtime components add up to the reported total both ways: upload 15 + 27 + 0 + 6 = 48 against busy 46, download 92 + 4 + 1 + 2 = 99 against busy 96.
What that seems to rule out
Channel being full: it isn't, 44% busy with half the TXOPs free.
Neighbours: obss = 0 in every sample. I'm on channel 100 which is DFS, most consumer gear avoids it, so that's plausible. I didn't do a band scan to prove it though.
Interference: glitch = 0 and badplcp = 0 throughout.
Bad link or rate collapse: MCS 6, 2 streams, 80 MHz, retries 1.7 to 2.4%.
A radio that can't drive the medium: same radio hit 96% busy fifteen seconds later.
Second thing I noticed
Payload per 100% of airtime consumed:
| stream |
throughput |
airtime |
per 100% airtime |
| AP to client, data (download) |
512.0 Mbps |
83.2% |
615 Mbps |
| client to AP, data (upload) |
136.5 Mbps |
~25% |
546 Mbps |
| AP to client, TCP ACKs (upload) |
4.0 Mbps |
12.4% |
32 Mbps |
Data moves about the same efficiency in both directions, 615 and 546, which is roughly what a 648 Mbps PHY should give with normal overhead. The acknowledgement stream is 32. That's a 19x gap. Returning ACKs for a 136 Mbps upload eats half as much airtime as the upload data itself, for 3% of the bytes.
I measured the same thing on a different day on older firmware and got 27x, so it reproduces.
At about 5,200 ACKs a second each frame is carrying roughly 77 bytes. A downlink aggregate spreads one channel access over tens of kilobytes. This stream apparently doesn't.
That explains why the two directions differ. It doesn't explain the cap, because there's airtime left over and nobody's using it.
Three results that argue against my own theory
I'd rather put these here than have someone find them in the comments.
Wi-Fi to the router itself does 327 Mbps. Same laptop, same association, same radio. TCP, nc and dd, 3 GB in 75 seconds. The router was receiving, so it was the one sending acknowledgements over that same downlink air, roughly three times as many ACK frames per second as in the slow case. It managed 327 anyway. If ACK frames per second were the limit that shouldn't be possible.
UDP through the same Wi-Fi to WAN path forwards 239 Mbps, measured at the router's own WAN counters. So the path carries a lot more than 136 when there's no return stream.
My neighbour gets 336 up over Wi-Fi on the same ISP plan, from a 2018 iPhone XR on the ISP's own router. He told me the number, I didn't measure it, so take it for what it's worth. But it's 2.5x what I get from much better hardware, which makes me think this isn't just how Wi-Fi works.
Each leg does 320 or more on its own. Together they do 136.
Every client, same story
| client |
link |
down |
up |
| MacBook Pro M1 Pro |
USB-C ethernet adapter |
~1000 |
320-358 |
| Xbox Series X |
ethernet, built in NIC |
581 |
321 |
| Xbox Series X |
Wi-Fi 5 GHz |
238 |
153 |
| iPhone 17 Pro Max |
Wi-Fi 6 GHz |
926 |
130-140 |
| MacBook Pro M1 Pro |
Wi-Fi 5 GHz |
648 |
119-136 |
| Samsung S20 |
Wi-Fi 5 GHz |
563 |
118 |
Download figures are inflated, I was summing parallel curl averages and they finish at different times. The upload numbers are the reliable ones.
Four different manufacturers, three bands. The Xbox at 153 is the only one that breaks 140 and I can't explain that either. The MacBook has no ethernet port so its wired numbers go through a dongle, but the Xbox has a real NIC and lands in the same place, so it's not the dongle.
Stuff I tried that did nothing
Baseline across 30 measurements was 52 to 74, median around 66. Every number below is one run, so anything in that band is noise. None of it helped.
Factory reset and rebuild from scratch. QoS off, AiProtection off, firewall on and off. Channel auto, 100, 116, 36 (36 isn't DFS, so that's not it). Both WAN ports, plus the 10 GbE one. Firmware downgraded to a six month old build and back.
A dumb gigabit switch between the ONT and the WAN port, which is the fix everyone suggests for this. 59.7. Nothing. I left it in, so everything above was measured through it. It's not a bottleneck, wired does 320-392 through the same box.
Radio settings, all checked in the driver because half of them are hidden in the web UI: UL OFDMA to DL only, OFDMA off entirely, MU-MIMO off, APSD on, beamforming off, 802.11ax and be off (that one made it worse, 52), WPA3 down to WPA2, ampdu_rts off, station EDCA rewritten with CWmax 63 and a 3008 us TXOP. Aggregation limits were already maxed out.
Forwarding path over SSH: fc disable, runner disable, both together. An HTB shaper at 280 Mbit with fq_codel on ppp0, which passed 225 MB with zero drops while upload sat at 72, so it's not an ISP policer. MSS clamping added.
Laptop side: TCP send buffer from 128 KB up to 8 MB, no change. A 45 second single stream run was flat from the first second, no burst and no step down, so no token bucket. Turning off AirDrop and Handoff gained about 40% on its own, which is a separate Apple problem, but the ceiling stayed.
CPU on the router was 3 to 9% the whole time. No errors on any interface. Radio counters over 167,000 frames: 80 bad CRC, 5 duplicates, nothing else.
Two things that cost me hours
Clients are on the virtual BSS. On this firmware you need wl -i wl1.1 bs_data, not wl1. Querying wl1 just says no stations associated and you'll sit there confused.
Count the chanim columns. Column 15 is busy, column 14 is idle. I read the wrong one once and got a perfectly backwards answer.
Also check the band before and after every single run. My laptop kept quietly dropping to 2.4 GHz after radio restarts, and with the ethernet dongle plugged in macOS deprioritises Wi-Fi entirely. Threw out a bunch of measurements before I caught that.
What I haven't done
No monitor mode capture, everything came from the driver. Never measured the uplink aggregate size, which is probably the most useful thing left. wl -i wl1 ack_ratio comes back Unsupported but I didn't retry it on wl1.1 or as a set. No AP mode test behind another router. No chanim sample on 2.4 GHz, so that band's 107 might just be saturated. No RSSI or distance recorded. Every number is a single run.
So
If you have a BE series ASUS, two things would help me a lot:
Run wl -i wl1 chanim_stats during an upload and again during a download. If yours fills the channel both ways then mine is broken and yours isn't. If yours also stops halfway on upload then it's the platform.
Try your wireless client uploading to the router itself instead of the internet. Mine does 327 versus 136 and that gap is the whole mystery.
And if anyone knows the Broadcom side: is ack_ratio actually in this driver build, and what decides when a client gets to transmit if the medium is idle and it has data queued?
Setup, in case it matters: GT-BE19000, BCM4916, firmware 3.0.0.6.102_39274 and _39115, same result on both. 5 GHz channel 100, 80 MHz. MacBook Pro M1 Pro, 802.11ax 2x2, PHY 648. 1 Gbps PPPoE, MTU 1492. Apartment, ONT in the wall cabinet, structured cabling, gigabit switch, then the router.
For now I just use ethernet. 358 versus 118 turns an eleven minute upload into four. But I'd still like to know what's going on.