WireGuard Handshake Timeout — Tunnel Not Establishing
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://ipfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://ipfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://ipfyi.com/entity//)
Use the native HTML custom element.
A WireGuard VPN tunnel fails to establish because the initial cryptographic handshake never completes. The client sends handshake initiation packets but receives no response from the server peer, resulting in a tunnel that shows `(none)` for the latest handshake in `wg show` and no ability to pass traffic. This is one of the most common WireGuard issues and usually has a network or configuration cause rather than a software bug.
Symptoms
- ⚠ `wg show` on the client displays `latest handshake: (none)` for the peer
- ⚠ Ping to the VPN gateway address (e.g., 10.8.0.1) fails with 100% packet loss
- ⚠ No traffic counters increment in `wg show` (transfer stays at 0 B received)
- ⚠ WireGuard logs show repeated 'Sending handshake initiation' without a corresponding response
- ⚠ Tunnel works from one network but not another (e.g., works on LAN, fails on mobile data)
- ⚠ Server-side `wg show` never lists a recent handshake from the expected client public key
Possible Root Causes
- • Firewall on the server (iptables, nftables, cloud Security Group) blocking inbound UDP on the WireGuard port
- • Incorrect public key in the peer configuration — keys are asymmetric and must cross-reference correctly
- • Server has a dynamic IP and the client's Endpoint is outdated; WireGuard has no built-in DNS re-resolution
- • NAT or stateful firewall between client and server dropping UDP sessions before the handshake completes
- • Server's WireGuard interface is not listening (service not running, config syntax error, or wrong port)
Diagnosis Steps
Step 1: Check WireGuard Status on Both Ends
# On the client
sudo wg show
# Expected output when tunnel is up:
# peer: <server-public-key>
# endpoint: 203.0.113.1:51820
# allowed ips: 0.0.0.0/0
# latest handshake: 23 seconds ago
# transfer: 1.23 MiB received, 456 KiB sent
# On the server (SSH in separately)
sudo wg show
# Check if client's public key appears and has a recent handshake
Step 2: Verify UDP Port Reachability
WireGuard uses UDP (default port 51820). TCP tools like telnet/curl won't work — use nc:
# From the client machine, test if the server's UDP port is open
nc -zvu 203.0.113.1 51820
# "Connection to 203.0.113.1 51820 port [udp/--] succeeded" = reachable
# Alternative: send a UDP packet and watch server-side tcpdump
# On server:
sudo tcpdump -n -i eth0 udp port 51820
# On client: attempt wg connection and observe if packets arrive
Step 3: Check Server Firewall
# On the server — list iptables/nftables rules
sudo iptables -L -n -v | grep 51820
sudo nftables list ruleset | grep 51820
# AWS / cloud: check Security Group rules in the console for UDP 51820
# ufw:
sudo ufw status verbose | grep 51820
Step 4: Validate Configuration Consistency
# Server /etc/wireguard/wg0.conf
sudo cat /etc/wireguard/wg0.conf
# Verify:
# 1. Server ListenPort matches what the client's Endpoint uses
# 2. Client's PublicKey in the server [Peer] block is correct
# 3. Server's PublicKey in the client [Peer] block is correct
# 4. AllowedIPs on the server peer entry includes the client's Address
# Decode and display a WireGuard public key from a private key:
wg pubkey < /etc/wireguard/server_private_key
Step 5: Test Bidirectional Connectivity
# From server, attempt to ping the client's VPN address
ping -c4 10.8.0.2
# If ping fails even after handshake, check AllowedIPs routing
ip route show table all | grep wg0
Solution
Fix 1: Open the Firewall Port
# iptables (persistent)
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT
sudo iptables -A FORWARD -i wg0 -j ACCEPT
sudo iptables -A FORWARD -o wg0 -j ACCEPT
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sudo netfilter-persistent save
# ufw
sudo ufw allow 51820/udp
# AWS Security Group: add inbound rule — Type: Custom UDP, Port: 51820, Source: 0.0.0.0/0
Fix 2: Correct Public Keys
# Regenerate keys if unsure
wg genkey | tee /etc/wireguard/client_private.key | wg pubkey > /etc/wireguard/client_public.key
cat /etc/wireguard/client_public.key # This goes in the server's [Peer] PublicKey
# Verify server public key
wg pubkey < /etc/wireguard/server_private.key # This goes in the client's [Peer] PublicKey
Fix 3: Use a Hostname for Dynamic Server IPs
In the client config, use a hostname instead of a bare IP:
[Peer]
PublicKey = <server-public-key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
WireGuard re-resolves the hostname on each handshake attempt. PersistentKeepalive = 25 also helps keep the tunnel alive through NAT.
Fix 4: Enable IP Forwarding on the Server
# Check current state
sysctl net.ipv4.ip_forward
# Enable (persistent)
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf
# Restart WireGuard
sudo wg-quick down wg0 && sudo wg-quick up wg0
Prevention
- Use a static public IP or a stable DDNS hostname for the WireGuard server endpoint to avoid stale IP issues
- Set
PersistentKeepalive = 25on mobile or NAT-traversal clients to maintain the tunnel through stateful firewalls - Store configuration in a version-controlled secrets manager and validate key pairs with
wg pubkeybefore deploying - Monitor the tunnel with a cron job that pings the server VPN IP and alerts if no response for 2 consecutive checks
- Test connectivity from a separate network (mobile hotspot) immediately after setup to catch firewall issues early