Symptom
pingandTest-NetConnection -Port 443succeed 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.
Step 1: confirm it is size-related (5 minutes)
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.