The Azure side of this lives in IKEDiagnosticLog. Turn on diagnostic settings for the gateway pointed at a Log Analytics workspace, then run the query from Troubleshoot Azure VPN Gateway using diagnostic logs:
AzureDiagnostics
| where Category == "IKEDiagnosticLog"
| extend Message1=Message
| parse Message with * "Remote " RemoteIP ":" * "500: Local " LocalIP ":" * "500: " Message2
| extend Event = iif(Message has "SESSION_ID",Message2,Message1)
| project TimeGenerated, RemoteIP, LocalIP, Event, Level
| sort by TimeGenerated asc
Filter RemoteIP to your FortiGate’s public address. In the IKEDiagnosticLog, every event is prefixed by who acted: [RECEIVED] means Azure got a packet from your on‑premises device, and [SEND] means Azure sent one.
That’s the part your packet capture can’t tell you. If you see [RECEIVED] entries for that IP, Azure is getting your SA_INIT, so the issue is in the negotiation. Look for the entry where rCookie = 0 which marks the start of each attempt. If you see nothing at all for that IP, Azure never received the packets. In that case, the shared key and IPsec policy don’t matter yet; the question becomes whether Azure has the same peer address you see as the source in your capture.
You also don’t need to time the capture. Azure retries every few seconds while a tunnel is failing, so there’s always a fresh negotiation in the logs.
One thing to check first: policy‑based gateways only produce GatewayDiagnosticLog and RouteDiagnosticLog. If this gateway is policy‑based, IKEDiagnosticLog won’t appear.
For what it’s worth, your capture already rules out a couple of common causes. A shared‑key mismatch gets you a reply followed by an auth failure, and a proposal mismatch gets you a reply or a notify. Silence usually means the packets aren’t being matched to a known peer at all.
Help make this community better for everyone: if this answer resolved your issue, please accept it or leave an upvote. If not, share more details in a comment so we can continue the discussion and find the right solution.