VPNSmith
self-host-vpnINFO

WireGuard handshake did not complete: the full fix list (2026)

WireGuard handshake did not complete? Ordered checklist: firewall, port, keys, AllowedIPs, NAT, clock, MTU. Diagnose with wg show and fix it in minutes.

By Eric Gerard · Founder · VPNSmith — Self-host VPN & GDPR VPS specialist9 min readPhoto via Unsplash

Affiliate disclosure — This post contains Contabo affiliate links. If you grab a VPS through them, we earn a commission at no extra cost to you. Every command and config below is documented from official WireGuard sources and written to be reproducible on your own VPS.

You typed wg show, you see your peer, and under it sits the line that ruins your evening: latest handshake is empty, or wg-quick warns handshake did not complete. Your tunnel is up on paper but no traffic flows. The good news: WireGuard fails for a short, finite list of reasons, and they fall in a predictable order. This guide walks that order from most-common to least-common, so you stop guessing and fix it in minutes.

WireGuard is silent by design — it sends nothing until there is data to carry, and it never logs a friendly "connection refused". That silence is what makes a failed handshake feel mysterious. Almost always it is a network-reachability problem (firewall, port, NAT, routing), not a cryptography problem. Work the list top to bottom and you will catch it.

First, read the actual state with wg show

Before changing anything, look at what WireGuard already tells you. On both ends:

sudo wg show

You are reading three things:

  • latest handshake — empty or older than ~2 minutes = the tunnel is down. Healthy = within the last 120 seconds.
  • transfer0 B received means your packets never came back. Sent-but-not-received is the signature of a one-way firewall or NAT block.
  • endpoint — on the server, this should show the client's current public IP:port once a packet arrives. If it never populates, the client's initiation never reached you.

Keep this terminal open. After each fix below, re-run wg show and watch the latest handshake line. That is your single source of truth — not the connection icon, not the app.

A 3D mesh of connected cube-shaped nodes linked by thin lines on a black background
A 3D mesh of connected cube-shaped nodes linked by thin lines on a black background

Cause 1 — The UDP port is blocked (the #1 culprit)

WireGuard speaks UDP on a single port — 51820 by default. If that port is filtered anywhere on the path, the initiation packet dies and you get exactly the symptom you have. For the default, how to change it and how to open it correctly, see what port WireGuard uses and how to open it. There are usually two firewalls to check, and people forget the first one:

Cloud provider firewall (the one most often missed). Contabo, Hetzner, OVH, AWS — they all have a network-level firewall or security group in front of your VPS. A rule allowing UDP 51820 from anywhere must exist there, separate from the OS firewall. On most Contabo VPS images there is no provider firewall by default (good), but if you enabled one, add the UDP rule.

OS firewall on the server. Check and allow:

# ufw (Debian/Ubuntu)
sudo ufw allow 51820/udp
sudo ufw reload

# firewalld (Rocky/Alma/Fedora)
sudo firewall-cmd --add-port=51820/udp --permanent
sudo firewall-cmd --reload

Quick proof the port is reachable from the outside — from your client machine:

# sends a UDP probe; "open|filtered" with no reply is inconclusive,
# but "open" or a returned packet confirms reachability
nc -u -z -v YOUR_SERVER_IP 51820

A cleaner test: run sudo tcpdump -n -i eth0 udp port 51820 on the server, then connect from the client. If you see incoming packets, the port is open and you move to the next cause. If you see nothing, the packet is being dropped before it reaches WireGuard — stay on this cause.

Cause 2 — Wrong Endpoint on the client

The client's [Peer] block needs the server's real public IP (or DNS name) and the exact ListenPort:

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = 203.0.113.10:51820
AllowedIPs = 0.0.0.0/0

Common mistakes that produce a dead handshake:

  • Endpoint points to the server's private LAN IP (10.x / 192.168.x) instead of the public one.
  • A typo in the port, or the server actually listens on a different ListenPort.
  • The server's public IP changed (some VPS reinstalls reassign it). Confirm with curl -4 ifconfig.co on the server, then compare to the client's Endpoint.

The server peer block has no Endpoint line (the server learns it when the client's packet arrives) — adding one there is a frequent copy-paste error.

Cause 3 — AllowedIPs are wrong

AllowedIPs is a cryptographic routing table, not a permission list, and getting it wrong silently breaks return traffic:

  • On the server, the peer's AllowedIPs must list that client's tunnel address only, e.g. 10.66.66.2/32. If two peers share an overlapping range, the server sends replies to the wrong one and the handshake "completes" then dies.
  • On the client, AllowedIPs = 0.0.0.0/0 routes everything through the tunnel (full VPN). If you want split tunnelling, list only the subnets you actually route — see our split-tunnel routing guide.

A handshake that briefly succeeds and then stalls is the classic signature of overlapping server-side AllowedIPs. Make every peer's range unique.

Cause 4 — NAT timeout (works for 2 minutes, then dies)

If your client is behind NAT (home router, 4G/5G, hotel Wi-Fi) and the link goes idle, the router drops the UDP mapping. The server then has no path back to the client and the handshake silently expires. The fix lives on the peer that sits behind NAT:

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = 203.0.113.10:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

PersistentKeepalive = 25 sends a tiny packet every 25 seconds, holding the NAT mapping open. Twenty-five seconds is below every common NAT timeout. Add it on roadwarrior clients and on any peer behind a restrictive router. The server-side peer usually does not need it.

Cause 5 — IP forwarding is off on the server

If the handshake completes but you cannot reach the internet through the tunnel, the server is not forwarding packets between the WireGuard interface and eth0. Enable it:

echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl --system

Confirm: sysctl net.ipv4.ip_forward must return 1. Pair it with the masquerade rule in your PostUp (the ready-to-use config templates ship these lines correctly):

PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Cause 6 — Clock skew

WireGuard's handshake uses timestamps to block replay attacks. If the server clock is off by more than a couple of minutes — common on fresh VPS images or VMs that paused — handshakes are rejected as stale. Fix the clock:

sudo timedatectl set-ntp true
timedatectl status   # System clock synchronized: yes

This one is sneaky because everything else looks perfect. If you have triple-checked the port, keys and routing and still get nothing, check the clock before despairing.

Cause 7 — Keys are mismatched (check this last)

People reach for keys first; check them last, because a key error is rarer than the six causes above and produces the same symptom. The rule is simple:

  • The server's [Peer] PublicKey = the public key derived from the client's PrivateKey.
  • The client's [Peer] PublicKey = the public key derived from the server's PrivateKey.

Regenerate and re-derive to be certain:

# on each machine, derive the public key from its own private key
echo "PRIVATE_KEY_OF_THIS_HOST" | wg pubkey

Compare that output to the PublicKey the other side has for you. A single swapped or truncated key breaks the handshake completely. While you are at it, a PresharedKey (if used) must be identical on both peers — a mismatch there also kills the handshake.

Cause 8 — MTU breaks the tunnel right after the handshake

Strictly, MTU rarely blocks the handshake (those packets are small). But it routinely breaks things the moment real traffic flows: handshake completes, ping works, then web pages hang forever. That is fragmentation. Lower the client MTU:

[Interface]
MTU = 1380

Find the right value with a do-not-fragment ping to the server's tunnel IP, shrinking until it passes:

ping -M do -s 1372 10.66.66.1

1420 suits most fibre links; 1380 is a safe default; PPPoE and some mobile carriers need 1280. Our config templates guide explains MTU tuning per link type.

The 60-second diagnostic order

When a handshake fails, run this exact sequence and stop at the first thing that's wrong:

  1. wg show on both sides — is there any latest handshake, any received bytes?
  2. tcpdump udp port 51820 on the server while the client connects — do packets arrive?
  3. If no packets arrive → firewall / port / Endpoint (Causes 1–2).
  4. If packets arrive but no reply gets back → server-side AllowedIPs, NAT, return route (Causes 3–4).
  5. If handshake completes but no internetip_forward + masquerade (Cause 5).
  6. If everything looks right and still nothing → clock skew, then keys, then MTU (Causes 6–8).

This order maps to how often each cause actually appears in real self-host setups — work it top to bottom and you will not waste time.

Build it right from the start

Most failed handshakes come from hand-stitching a config out of three contradictory tutorials. Starting from a known-good base on a clean VPS removes 90% of the surprises. A Contabo VPS S at €4.99/month gives you a public IPv4, full root, and no provider firewall to fight — exactly the conditions where WireGuard "just works". Follow the step-by-step Contabo + WireGuard setup and paste a vetted config from the templates guide, and the handshake completes on the first try.

Going further

Sources and references:


Published 2026-06-23. Diagnostic order validated on Debian 12 and Ubuntu 24.04 servers with a Contabo VPS S, against WireGuard clients on Linux, Windows 11, macOS and Android. Your link conditions may differ — always confirm with wg show and tcpdump before considering a fix final.

Reminder: running WireGuard and self-hosting a VPN is legal in the EU, US, Canada and most democratic countries. VPNSmith publishes this content for educational purposes.

★ Nuremberg GDPR datacenter · ✓ Dedicated IPv4 included · 200+ Mbps guaranteed

Self-host your VPN on your own VPS → ContaboFull root access · public IPv4 · pick your region