VPN works on Wi-Fi but not on mobile data
Mobile networks differ from home ones in three ways that break tunnels: carrier-grade NAT with short timeouts, IPv6-only cellular cores where an IPv4-only endpoint is unreachable, and aggressive filtering of unusual UDP. Each has a distinct symptom and a distinct fix.
4 min read
A configuration that works perfectly at home and fails on cellular is not a broken configuration. Mobile networks are built differently from home broadband in ways that matter specifically to tunnels, and there are three of them.
Cause one: carrier-grade NAT with short timeouts
Mobile operators ran out of IPv4 addresses long ago and put subscribers behind
shared address space, defined in RFC 6598 as 100.64.0.0/10. Your handset does
not have a public address; the carrier translates on the way out.
Translation tables are finite, so entries expire. Home routers commonly hold a UDP mapping for several minutes. Carrier NAT sometimes drops one in under a minute, because it is managing millions of subscribers rather than a household.
Symptom: the tunnel connects, works, and dies after a short idle period. Reconnecting works immediately.
Fix: a keepalive. WireGuard's PersistentKeepalive = 25 sends an empty
packet every twenty-five seconds to hold the mapping open. If your app exposes
the setting, this is what it is for. It costs a trivial amount of data and a
small amount of battery.
Cause two: an IPv6-only mobile core
Several large carriers run IPv6-only to the handset and translate to IPv4 at the network edge using NAT64 and DNS64. Your phone genuinely has no IPv4 address.
That usually works transparently, because DNS64 synthesises an IPv6 address for any IPv4-only destination you look up. It breaks when a VPN endpoint is configured as a literal IPv4 address, because nothing looks it up and therefore nothing synthesises anything.
Symptom: the handshake never completes on cellular and works on Wi-Fi, with the same config, and the endpoint in the config is an IP address rather than a hostname.
Fix: use a hostname endpoint so DNS64 can do its job, or use an endpoint the provider publishes with an AAAA record.
Check it: on Android, Settings, About phone, Status shows the addresses. An
address beginning 2 and no IPv4 address is an IPv6-only attachment.
Cause three: UDP filtering
Some carriers, and more often some roaming partners, filter or rate-limit unusual UDP traffic. WireGuard is UDP with no fallback, so this is fatal to it specifically.
Symptom: consistent handshake failure on one carrier, works on another SIM or on Wi-Fi.
Fix: an OpenVPN endpoint on TCP 443, if your provider offers one. There is no WireGuard-only answer, because the protocol has no TCP mode by design.
Cause four: MTU, which is different on cellular
Mobile links often carry a smaller MTU than Ethernet, and some carriers apply tunnelling of their own that reduces it further. A tunnel MTU that is correct on Wi-Fi can be too large on cellular.
Symptom: the tunnel connects and small requests work, but pages with images hang. This is the classic path MTU black hole, and it appears on mobile more often than anywhere else.
Fix: drop the tunnel MTU to 1380, or 1280 to test. Many clients let you set this per connection.
Cause five: battery optimisation
On Android, aggressive power management can suspend the VPN app in the background, which drops the tunnel while the screen is off. This looks like a mobile-data problem because it happens when the phone is in a pocket rather than in front of you.
Fix: exclude the app from battery optimisation and enable Always-on VPN.
Cause six: a data saver or private relay
Data saver modes route traffic through a carrier or vendor proxy. iCloud Private Relay does something similar for Safari. Either can interact badly with a tunnel, though both normally defer to a VPN.
Fix: turn them off while testing so you are diagnosing one thing at a time.
The order to work through
- Does the handshake complete at all? If never on cellular, look at IPv6-only and UDP filtering.
- Does it complete and then die when idle? Keepalive.
- Does it stay up but stall on large pages? MTU.
- Does it only fail when the screen is off? Battery optimisation.
- Try a second SIM or a friend's hotspot. If it works there, the carrier is the variable and no local setting will change it.
Confirm the result
With the tunnel up on cellular, open what is my IP. The address should be the server's, and importantly it should still be the server's after the phone has been idle in your pocket for ten minutes. A tunnel that passes the test immediately and fails it later is the carrier NAT case, and the keepalive is the fix.