The tunnel came up, traffic flowed, and later the log says peer SA proposal not match local policy. Most people read that line as proof the two configurations never matched. It usually means something narrower: they matched for the first CHILD SA and stopped matching at the first renewal, because the first association never needed the exchange that later ones perform. That distinction decides where you look.

The first CHILD SA inherits, later ones negotiate

In IKEv2 the initial CHILD SA is created during IKE_AUTH, and its keys are derived from the IKE SA keying material. There is no separate Diffie-Hellman exchange at that point, so a PFS group that one peer cannot accept is simply not exercised yet. The tunnel looks healthy because the requirement you will later fail was never tested.

A CHILD_SA rekey is a different message sequence. When PFS is configured, the peers run a fresh key exchange and must agree on a group both sides accept, plus the ESP proposal for the new association. That is the moment the mismatch becomes visible, and it is why the error names a proposal rather than a route.

So "it worked yesterday" tells you nothing about the proposal. It tells you the initial exchange succeeded, which you already knew.

Read the failed exchange, not the first ping

Collect the successful IKE authentication, the initial CHILD SA and the failed replacement from both ends before changing anything. Then name the operation precisely: IKE SA rekey, IKE reauthentication and CHILD SA rekey are three different events, and "phase 2" covers all of them in casual conversation.

Compare the fields below for the connection that failed, not for the tunnel in general.

LayerValues to compare
IKEVersion, encryption and integrity or PRF arrangement, DH group
IPsec / CHILDESP encryption and integrity, intended PFS or key-exchange group
Protected trafficLocal and remote selectors, plus any policy-based selector setting

On FortiGate, open the phase-2 proposal, the PFS setting and the accepted DH groups for that tunnel. Read the loaded values rather than inferring them from a connection that established earlier. A screenshot of the GUI page is weaker evidence than the running configuration, because the two can disagree after an upgrade. Export the section you changed and keep it with the ticket.

Azure's default policy is still a policy

No custom policy attached to the connection does not mean Azure applies none. The connection falls back to the gateway's default proposal set, which may be broader or narrower than what your FortiGate offers. If the two sets overlap for IKE but not for ESP with PFS, you get exactly this failure pattern.

This read-only view shows the policy actually attached, without dumping secrets:

Get-AzVirtualNetworkGatewayConnection -Name 'Branch' -ResourceGroupName 'NetworkRG' |
Select-Object Name, ConnectionStatus, IpsecPolicies

Use your real resource names. When an explicit policy is needed, set it on the connection resource. It is not a gateway-wide switch, and it does not silently apply to other tunnels on the same gateway.

In the portal, that connection's Configuration page is where a custom IPsec/IKE policy goes. Microsoft's custom-policy guide lists the supported parameters and SKU requirements. Azure takes one complete combination per connection, so you specify the IKE fields and the IPsec fields together, not one at a time.

PFS is a requirement, not a switch to flip

If your security baseline requires PFS, the fix is a group both peers accept on both sides, expressed through a matching policy. Turning PFS off to make the error disappear changes the security property you were trying to keep, and it usually reappears as a different mismatch later.

One Azure-specific trap: when you choose GCM for ESP, the encryption and integrity selections have to name the same GCM algorithm and key length. Mixing a GCM cipher with a separate integrity algorithm produces a combination the service rejects, which looks like a peer mismatch until you read the policy closely.

Choose the strongest combination that both ends support and your requirement allows, then write it down in the change record. The next person will compare against that record, not against a memory of a working tunnel. Put the PFS group and the ESP proposal in it, not just the policy name. When someone later asks why an audit failed or why a rekey is slow, that line answers both questions.

Verify the exchange that failed

Schedule the change with a recovery path, because editing the policy can interrupt the tunnel you are trying to fix. After traffic returns, wait for or trigger a CHILD_SA renewal and confirm the new association is established with the intended PFS group. Then confirm application traffic continues across it.

Two red herrings are worth naming. SA lifetimes are local specifications, so unequal values are normal and changing them only moves when the problem appears. DPD detects whether a peer is alive; raising its timeout does not align ESP or PFS choices.

Record the negotiated result and the next event after the change. If the connection now fails before IKE authentication completes, you are looking at the IKE settings you just edited, not at the original CHILD-renewal failure.

ບົດຄວາມທີ່ກ່ຽວຂ້ອງ