Home / Azure

AzureRunbookAdvanced

Small requests work but large transfers hang over Azure VPN or ExpressRoute - finding and fixing an MTU/MSS black hole

TCP connects, pings work, but TLS handshakes, SMB copies or database result sets stall across the hybrid link. Prove the path MTU, then clamp MSS instead of raising MTU.

Deepak Bhardwaj7 min read

Applies toAzure VPN Gateway (site-to-site), ExpressRoute private peering (including IPsec over ExpressRoute), third-party NVAs in Azure, Linux and Windows Server VMs

Symptom

  • ping and Test-NetConnection -Port 443 succeed between on-premises and Azure.
  • HTTPS calls hang after the TCP handshake, often at the TLS Server Hello because the certificate chain fills a full-size packet.
  • SMB file copies start then stall; RDP connects and then freezes on the first screen redraw.
  • Small SQL queries return, large result sets time out.
  • It only happens across one path: the VPN, a new NVA, IPsec over ExpressRoute, or a provider change.

That pattern means full-size packets are dropped somewhere and the sender never learns to send smaller ones. Each tunnel or overlay adds headers, so the usable MTU on the path is below 1,500. Path MTU discovery (PMTUD) depends on ICMP "fragmentation needed" messages getting back to the sender; if a firewall drops them, the connection black-holes.

Reference numbers

Microsoft's TCP/IP tuning guidance for Azure:

Item Value
Azure VM default MTU 1,500
Recommended IPsec tunnel interface MTU (Azure VPN) 1,400
Recommended TCP MSS clamp (Azure VPN) 1,350

Larger VM MTUs exist for specific NICs but only apply to traffic that stays inside the virtual network, not traffic through gateways or to the internet. Microsoft advises against raising the VM MTU for general use, partly because fragmented packets leave the accelerated networking fast path.

From an Azure VM to an on-premises host, send packets with Don't Fragment set and shrink until they pass. Payload + 28 bytes (IP + ICMP headers) = packet size.

Linux:

ping -M do -s 1472 -c 3 10.20.0.15   # 1500-byte packet
ping -M do -s 1372 -c 3 10.20.0.15   # 1400
ping -M do -s 1322 -c 3 10.20.0.15   # 1350
tracepath -n 10.20.0.15              # reports pmtu per hop when ICMP comes back

Windows:

ping -f -l 1472 -n 3 10.20.0.15
ping -f -l 1372 -n 3 10.20.0.15

How to read the results:

Result at 1472 Meaning
Reply Path carries 1,500; look elsewhere (NSG, firewall, app timeouts)
"Message too long" / "Packet needs to be fragmented but DF set" PMTUD is working; something reports a smaller MTU. Usually fine for TCP unless a device in the middle ignores it
Silent timeout, but smaller sizes reply Black hole: packets dropped and no ICMP returned. This is the bug

Run the test in both directions. On-premises to Azure often has a different path (different firewall, different tunnel) from Azure to on-premises.

Step 2: check what each host thinks its MTU is

ip link show eth0 | grep -o 'mtu [0-9]*'
ip route get 10.20.0.15            # shows a cached "mtu" if PMTUD has learned one
netsh interface ipv4 show subinterfaces

On Azure VMs with accelerated networking, Linux shows the synthetic eth0 and a Mellanox VF interface. Both should be 1,500 unless you changed them on purpose. If someone set 9,000 on a VM "for performance", traffic to anything outside the VNet will depend on PMTUD and is exposed to exactly this problem; set it back.

Step 3: capture the stall

Use Network Watcher packet capture on the Azure VM, filtered to the remote host, and reproduce the hang:

az network watcher packet-capture create -g rg-app --vm app-vm-01 \
  -n mtu-test --storage-account stdiagcaptures \
  --filters '[{"protocol":"TCP","remoteIPAddress":"10.20.0.15"}]' \
  --time-limit 300

In Wireshark, look at the SYN and SYN-ACK MSS options and then the data:

  • SYN from Azure advertises MSS 1460, SYN-ACK from on-premises advertises 1460, nobody clamps.
  • Large segments leave the sender, then retransmissions of the same sequence number repeat with growing gaps.
  • No ICMP type 3 code 4 ever arrives.

That is the proof you need for the network team.

Step 4: fix it

The fix is to make TCP choose smaller segments at handshake time so PMTUD is never needed. Clamp the MSS on a device that sees every SYN on the path.

On-premises VPN device

Set the tunnel interface MTU to 1,400 and MSS clamping to 1,350, per Microsoft's guidance. Syntax depends on the vendor; for example, on Cisco IOS:

interface Tunnel10
 ip mtu 1400
 ip tcp adjust-mss 1350

Check your vendor's validated configuration for Azure VPN; the commands differ across platforms and firmware.

Linux NVA in Azure (or on-premises Linux router)

iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --set-mss 1350
# or derive it from the outgoing route MTU
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --clamp-mss-to-pmtu

Make the rule persistent (iptables-save, nftables config or your NVA's own CLI). Third-party NVAs (Palo Alto, Fortinet, Check Point) have their own MSS adjust settings per interface or zone.

IPsec over ExpressRoute and provider overlays

ExpressRoute private peering itself is designed for a 1,500-byte MTU, but IPsec over ExpressRoute, SD-WAN overlays or provider encapsulation reduce it. Apply the same clamp on the device that builds the overlay.

Let ICMP through

Separately, allow ICMP type 3 code 4 (IPv4) and ICMPv6 Packet Too Big through on-premises firewalls, NVAs and any NSG with a broad inbound deny. Many firewalls drop ICMP by default, and that is what turns a smaller MTU into a black hole. Clamping fixes TCP; ICMP fixes UDP and anything that ignores MSS.

Warning

Lowering the MTU on individual Azure VMs to "fix" the hybrid path is a workaround with side effects: every VM needs it, new VMs won't have it, and you lose throughput on in-VNet traffic. Fix the tunnel edge instead.

Step 5: verify

ping -M do -s 1322 -c 3 10.20.0.15                # must pass
curl -sv https://onprem-app.corp.local -o /dev/null 2>&1 | grep -E "SSL connection|HTTP/"

In a new capture, the SYN-ACK (or SYN) crossing the tunnel should now show MSS 1350, and large transfers complete without retransmission storms.

Symptom → cause → fix

Symptom Likely cause Fix
TLS hangs after Client Hello across VPN Server Hello + cert chain exceeds path MTU, ICMP dropped MSS clamp 1,350 at tunnel edge
Works one direction only Clamp configured on one side only Clamp on both tunnel endpoints or on the single device in the path
Broke after adding an NVA / SD-WAN Extra encapsulation, no clamp MSS adjust on the NVA
Broke after VM MTU change to 9,000 Larger segments outside VNet Revert to 1,500
UDP app (DNS over large responses, VoIP) fails No MSS for UDP, ICMP blocked Allow ICMP Packet Too Big; use TCP fallback for DNS

Prevent it next time

  • Put MTU 1,400 / MSS 1,350 in the standard build for every Azure VPN tunnel, and verify it in change reviews.
  • Add a DF-ping test at 1,350 and 1,400 to the post-change checklist for any VPN, NVA or ExpressRoute work.
  • Keep VM MTU at the 1,500 default in your images unless a workload is proven to need more inside the VNet.
  • Document which devices clamp MSS on each hybrid path so the next person knows where to look.