This episode dissects the life of a WireGuard session: the one-round-trip noise IK handshake, the anti-DoS cookie mechanism, automatic rekeying every two minutes, and the state transitions from empty to data-received and timeout.

Every WireGuard data packet sits behind a session, and every session is born from a process called the handshake. Understanding the handshake means understanding why a connection is a few milliseconds slow at first, why an idle connection can "die," and how WireGuard survives attacks that flood it with handshake packets.
Episode 5 dissects the Noise IK handshake mechanism, the cookie mechanism as an anti-DoS shield, the automatic rekeying policy, and the state transition map of a session from birth to end.
Throughout this episode, remember that all these mechanisms run automatically inside the kernel. Your only role is to ensure the correct initial conditions — keys, endpoint, and firewall — and then let the protocol take care of itself.
The WireGuard handshake consists of just three messages: a handshake initiation (from the initiator), a handshake response (from the responder), and after that both parties already have session keys. From the initiator's point of view this is one round trip — unlike TLS, which can take several exchanges.
The process in the Noise IKpsk2 scheme:
wg show wg0 latest-handshakesThe output of wg show wg0 latest-handshakes shows the time of the last handshake as a UNIX timestamp. A value of zero means the peer has never handshaked — usually because the endpoint is wrong or the UDP port is closed.
After the handshake, if there is no data, WireGuard sends a keepalive packet roughly every 10 seconds so that NAT mappings and session state stay fresh. These keepalives do not count as transferred traffic.
These keepalives work together with PersistentKeepalive, covered in episode 7: the internal keepalive maintains the protocol's session state, while PersistentKeepalive maintains the NAT mapping so the session remains reachable from the outside.
Handshake initiation is computed with elliptic curve cryptography, which is fairly expensive. If an attacker floods a server with fake handshakes, the server can be exhausted. WireGuard dampens this with the cookie mechanism.
How it works: the server asks the responder to supply a cookie (a MAC value derived from the destination IP address) before accepting the next handshake. Because the cookie is bound to the IP address, an attacker spoofing addresses cannot complete the handshake. The mechanism is efficient: no per-requester session state needs to be stored.
Cookies appear when the server is under heavy handshake pressure or when the peer table is full. When you see a Handshake was rate limited message in the logs, that is the cookie mechanism working.
Important: the cookie mechanism is not protection against every kind of DoS attack; it is a specific dampener for handshake floods. This fits the WireGuard philosophy — focus on one problem and solve it well.
One practical note: the handshake age is not the only health indicator. The combination of latest-handshakes and a continuously growing transfer gives a more complete picture, and both will be used as the basis for monitoring in episodes 8 and 21.
Session keys are not used forever. WireGuard replaces keys automatically:
Rekeying preserves forward secrecy — the leak of one session key does not open other sessions.
A WireGuard session moves through simple states:
These transitions happen automatically in the kernel. You do not manage this state manually — all you observe is latest-handshakes and the output of wg show.
If wg show always shows a zero handshake, this is the usual troubleshooting order:
Endpoint in [Peer] point to the correct address and UDP port?ListenPort?PersistentKeepalive?If all of these are correct but the handshake still fails, set PersistentKeepalive = 25 on the client side and watch whether the endpoint on the server changes after the first packet arrives. A changing endpoint indicates the packet is arriving even though the handshake is not complete, so the problem lies in processing, not connectivity.
watch -n 2 "sudo wg show wg0 latest-handshakes"watch -n 2 refreshes the display every two seconds, so you can watch the handshake appear the moment the first connection is made.
Episode 5 dissected the life cycle of a WireGuard session: the one-round-trip Noise IK handshake, the cookie mechanism for holding back handshake floods, automatic rekeying, and the state transition map that runs inside the kernel.
Key takeaways:
latest-handshakes means no handshake has ever happened.In episode 6 we cover routing and allowed IPs — why AllowedIPs is not a firewall, how to use it for split tunneling, and how wg-quick interacts with ip route to build tunnel routes automatically.