WireGuard keepalive only sent one time, with handshake, not later?

Three MikroTiks, "2", "3", and "4"; "2" and "3" keep up a WireGuard tunnel each to "4"; "4" is a responder.

It works fine, with one exception: Although persistent-keepalive is set to 00:00:30 on both peer ends of each WireGuard tunnel, the only time either peer MikroTik logs the keepalive is right at the time of each handshake (every two minutes). It seems that a keepalive should be logged every 30 seconds, no?

"4" config:

interface=wg1 name="MikroTik2-WG" public-key={public key} endpoint-address="" endpoint-port=0 current-endpoint-address=80.41.162.160
current-endpoint-port=12345 allowed-address=192.168.254.0/24,192.168.255.142/32 persistent-keepalive=30s client-endpoint="" client-allowed-address=::/0 responder=yes
rx=764.2MiB tx=271.6MiB last-handshake=54s

"2" config:

interface=wg1 name="MikroTik4-WG" public-key="{public key}" http://endpoint-address=mikrotik4-dyn.felines.org endpoint-port=12345
current-endpoint-address=83.40.90.106 current-endpoint-port=12345 allowed-address=192.168.255.0/26,192.168.255.64/26,192.168.255.128/26,192.168.251.0/24 persistent-keepalive=30s
client-endpoint="" client-allowed-address=::/0 rx=266.4MiB tx=757.4MiB last-handshake=1m54s

Log on "4":

2026-06-12 22:34:10 wireguard,debug wg1: [MikroTik3B-WG] {pubkey}: Receiving handshake initiation from peer (95.33.33.196:59366) extra:0 (ein
val)
2026-06-12 22:34:10 wireguard,debug wg1: [MikroTik3B-WG] {pubkey}: Sending handshake response to peer (95.33.33.196:59366)
2026-06-12 22:34:10 wireguard,debug wg1: [MikroTik3B-WG] {pubkey}: Receiving keepalive packet from peer (95.33.33.196:59366)

2026-06-12 22:34:38 wireguard,debug wg1: [MikroTik3-WG] {pubkey}: Receiving handshake initiation from peer (73.80.148.50:12345) extra:0 (einv
al)
2026-06-12 22:34:38 wireguard,debug wg1: [MikroTik3-WG] {pubkey}: Sending handshake response to peer (73.80.148.50:12345)
2026-06-12 22:34:38 wireguard,debug wg1: [MikroTik3-WG] {pubkey}: Receiving keepalive packet from peer (73.80.148.50:12345)

2026-06-12 22:35:24 wireguard,debug wg1: [MikroTik2-WG] {pubkey}: Receiving handshake initiation from peer (83.41.122.160:12345) extra:0 (ein
val)
2026-06-12 22:35:24 wireguard,debug wg1: [MikroTik2-WG] {pubkey}: Sending handshake response to peer (83.41.122.160:12345)
2026-06-12 22:35:24 wireguard,debug wg1: [MikroTik2-WG] {pubkey}: Receiving keepalive packet from peer (83.41.122.160:12345)

2026-06-12 22:36:10 wireguard,debug wg1: [MikroTik3B-WG] {pubkey}: Receiving handshake initiation from peer (95.33.33.196:12345) extra:0 (ein
val)
2026-06-12 22:36:10 wireguard,debug wg1: [MikroTik3B-WG] {pubkey}: Sending handshake response to peer (95.33.33.196:12345)
2026-06-12 22:36:10 wireguard,debug wg1: [MikroTik3B-WG] {pubkey}: Receiving keepalive packet from peer (95.33.33.196:12345)

2026-06-12 22:36:38 wireguard,debug wg1: [MikroTik3-WG] {pubkey}: Receiving handshake initiation from peer (73.80.148.50:12345) extra:0 (einv
al)
2026-06-12 22:36:38 wireguard,debug wg1: [MikroTik3-WG] {pubkey}: Sending handshake response to peer (73.80.148.50:12345)
2026-06-12 22:36:38 wireguard,debug wg1: [MikroTik3-WG] {pubkey}: Receiving keepalive packet from peer (73.80.148.50:12345)

Log on "2" (not concurrent, but fully representative):

2026-06-12 22:37:24 wireguard,debug wg1: [MikroTik4-WG] {public key}: Sending handshake initiation to peer (83.40.90.106:12345)
2026-06-12 22:37:24 wireguard,debug wg1: [MikroTik4-WG] {public key}: Receiving handshake response from peer (83.40.90.106:12345)
2026-06-12 22:37:24 wireguard,debug wg1: [MikroTik4-WG] {public key}: Sending keepalive packet to peer (83.40.90.106:12345)

2026-06-12 22:39:24 wireguard,debug wg1: [MikroTik4-WG] {public key}: Sending handshake initiation to peer (83.40.90.106:12345)
2026-06-12 22:39:24 wireguard,debug wg1: [MikroTik4-WG] {public key}: Receiving handshake response from peer (83.40.90.106:12345)
2026-06-12 22:39:24 wireguard,debug wg1: [MikroTik4-WG] {public key}: Sending keepalive packet to peer (83.40.90.106:12345)

2026-06-12 22:41:24 wireguard,debug wg1: [MikroTik4-WG] {public key}: Sending handshake initiation to peer (83.40.90.106:12345)
2026-06-12 22:41:24 wireguard,debug wg1: [MikroTik4-WG] {public key}: Receiving handshake response from peer (83.40.90.106:12345)
2026-06-12 22:41:24 wireguard,debug wg1: [MikroTik4-WG] {public key}: Sending keepalive packet to peer (83.40.90.106:12345)

On both:

/system/logging/print where topics~"wireguard"

TOPICS ACTION

10 wireguard memory
debug

(The same is seen on the "3" <-> "4" WireGuard tunnel).

Why are keepalive packets only being sent once per handshake, right at the time of (immediately after) the handshake, instead of once every 30 seconds? And, why are keepalive packets only sent from "2" and "3", to "4" (the responder), and not also from "4" to "2" and to "3"?

thanks,

In the implementation used by Mikrotik, a keepalive is not sent right after a handshake. I think the lig shows that the handshake itself counts as a keepalive.

I haven't encountered a situation yet where a Mikrotik would fail to send keepalives as configured. My only guess would be that there is traffic (even if very little, even if it's only incidental) passing through your tunnel. A keepalive is only sent if the tunnel would be silent without it.

Hm, yeah, ok, it looks like it's a gap in RouterOS logging, that it doesn't actually debug log all keepalive packets. (And, possibly, also, that what it does log as a keepalive packet, immediately after each handshake, isn't strictly a keepalive packet);

Sniffing on the outgoing interface over which the RouterOS WireGuard local peer transmits to the remote ('server') peer, on a link which is normally very quiet:

[admin@MikroTik3] /tool/sniffer> pack print follow
TIME INTERFACE SRC-ADDRESS DST-ADDRESS IP-PROTOCOL SIZE CPU
1.989 bridge 10.0.0.5:12345 83.40.90.106:12345 udp 74 0
32.069 bridge 10.0.0.5:12345 83.40.90.106:12345 udp 74 0
62.149 bridge 10.0.0.5:12345 83.40.90.106:12345 udp 74 0
62.155 bridge 10.0.0.5:12345 83.40.90.106:12345 udp 190 0
62.283 bridge 10.0.0.5:12345 83.40.90.106:12345 udp 74 0

The 74-byte packets correspond to keepalive intervals. The 190-byte packet corresponds to a handshake. The RouterOS 7.23.1 log only shows a keepalive for the single 74-byte packet immediately after the handshake.

I'll file a bug report with MikroTik for their evaluation.

Well, that sort of clarifies things.

Do report back when you hear from them!

Reply from MikroTik support:

"WireGuard sends persistent keepalive packets correctly every 30 seconds, as verified by your packet capture. However, the wireguard,debug log does not log every keepalive transmission, which can make the debug output appear inconsistent with the configured keepalive interval."

So, yes, WireGuard logs are not useful for keepalive packet debugging.

My reply back to MikroTik:

"I propose that this should be a bug report/enhancement request; logging should be accurate, complete, and representative. Otherwise, instead of making diagnosis easier/better, it makes diagnosis harder/slower, which is the opposite of what logging is meant for."

MikroTik support's reply, to my assertion that logging "keepalive sent" should exactly match when keepalives are sent:

"That was specifically set due to requests from the users. We will think on how to improve it in future."

:face_with_spiral_eyes: