We had the same with tank level boxes in a pump yard and our network guy walked me through it.
Mechanism: with distance the signal-to-noise ratio drops. Wi-Fi then picks a slower, safer modulation and coding rate (rate adaptation), each symbol carries fewer bits, so the data rate falls from tens of Mbps to 1-6 Mbps. On top of that, weaker frames fail more often and get retried, and each retry costs airtime and backs off. So „weaker“ turns into „slower“, and twilson’s point is real: at 1 Mbps your sensors use far more of the channel per byte than a laptop.
What helped us, in order of effect:
Fewer, bigger messages. Batch 2-4 readings into one telemetry array with their ts and send every couple of minutes. Same data, a fraction of the frames. Each message also counts once against the monthly quota whatever it holds.
Keepalive at 60-120 s, not 15. The docs recommend something between 30 and 300 s, and a short keepalive on a slow link is what gives you the odd keepalive_timeout.
Wait for PUBACK before deleting a buffered reading. Hermetry acks only after the message is safely queued, and a device can only have a limited number of unacknowledged QoS 1 messages in flight (20 by default), so on a slow link don’t fire them off blindly.
Fix the radio path properly: a point-to-point bridge to a small AP in the yard, or one gateway in the yard collecting the boxes over RS-485 or a short-range radio and sending on its own link. We did the bridge, the boxes now connect at 65 Mbps.
MQTT has the keepalive and in-flight numbers.

