Enabling HTTP/2 and HTTP/3 (QUIC) on IIS in Windows Server: Registry, Ciphers, and Verification

HTTP/2 is enabled by default on Windows Server 2016 and later, but HTTP/3 is not, and both need specific registry keys to behave correctly behind a proxy or load balancer. This guide covers enabling HTTP/3 over QUIC on IIS, verifying HTTP/2 is actually negotiating, and the TLS cipher suites that must be present for either to work.

Prerequisites and version support

Windows ServerHTTP/2HTTP/3 (QUIC)Notes
2016Yes, on by defaultNoNeeds TLS 1.2+ ciphers
2019YesNoRegistry tuning available
2022YesYes (build 20348+)Enable via registry, IIS 10
2025YesYesBest QUIC support, HTTP.sys native

HTTP/2 requires HTTPS/TLS in practice — browsers will not negotiate h2 over cleartext, with one exception for h2c that IIS does not use. So TLS must be correct first. If HTTPS is not yet working, start with the IIS HTTPS bindings and certificates guide.

Step 1: confirm HTTP/2 in the registry

HTTP/2 settings live under HTTP.sys, not in IIS. Check the current state and set them explicitly.

# Inspect HTTP/2 parameters (HTTP.sys)
$base = 'HKLM:\SYSTEM\CurrentControlSet\Services\HTTP\Parameters'
Get-ItemProperty -Path $base |
  Select-Object EnableHttp2Tls, EnableHttp2Cleartext, Http2MaxSettingsPerFrame, Http2MaxSettingsPerMinute

# Enable HTTP/2 over TLS (default 1 on modern builds)
Set-ItemProperty -Path $base -Name EnableHttp2Tls -Value 1 -Type DWord
Set-ItemProperty -Path $base -Name EnableHttp2Cleartext -Value 0 -Type DWord

# Restart HTTP.sys
net stop http /y
net start http
iisreset /restart

Inside IIS Manager, each site also has per-binding HTTP/2 control under the site’s Bindings node — the “Disable HTTP/2” checkbox. Leave it unchecked unless a specific backend app breaks on h2 stream multiplexing.

Step 2: enable HTTP/3 over QUIC

QUIC runs over UDP 443, which means a completely different firewall consideration from the TCP 443 you already have open. Two things must be true: the registry keys below, and UDP 443 allowed inbound.

# Enable HTTP/3 over QUIC (Windows Server 2022 build 20348+ / 2025)
$base = 'HKLM:\SYSTEM\CurrentControlSet\Services\HTTP\Parameters'
Set-ItemProperty -Path $base -Name EnableHttp3 -Value 1 -Type DWord
Set-ItemProperty -Path $base -Name EnableQuic -Value 1 -Type DWord

# Allow QUIC through the firewall
New-NetFirewallRule -DisplayName "IIS HTTP/3 QUIC (UDP 443)" `
  -Direction Inbound -Protocol UDP -LocalPort 443 -Action Allow -Profile Any

Restart-Service http -Force
  • HTTP/3 is only negotiated after a browser has connected once over HTTP/2 — the Alt-Svc header tells it to try QUIC on the next request. Do not expect h3 on a cold first load.
  • If your VPS provider filters UDP, HTTP/3 will silently fall back to HTTP/2. Verify with a packet-level or dev-tools check rather than assuming.
  • Application Request Routing (ARR) and some WAF modules do not fully support QUIC; test reverse-proxy paths separately.

Step 3: the cipher suites both protocols require

HTTP/2’s RFC forbids cipher suites that browsers consider obsolete, and QUIC requires TLS 1.3 with AES-GCM or ChaCha20. If you removed TLS 1.3 or trimmed cipher suites too aggressively, HTTP/2 negotiation fails and browsers fall back to HTTP/1.1 without any obvious error. Confirm the state:

# Check TLS 1.2/1.3 and cipher suite order
Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -ErrorAction SilentlyContinue
Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -ErrorAction SilentlyContinue
Get-TlsCipherSuite | Where-Object Name -match 'AES_GCM|CHACHA20' |
  Select-Object Name, CipherSuitePosition

Verifying what the server actually negotiates

Server-side headers are not enough — you need to see the negotiated protocol. From a Windows box with the same TLS stack, use a quick TLS handshake probe, or from any machine use curl if available:

# From Linux/macOS or WSL: show negotiated protocol version
curl -sI --http2 https://example.com/ | head -1

# Confirm h3 is advertised
curl -sI https://example.com/ | Select-String -Pattern 'alt-svc'

In Chrome or Edge, open DevTools, go to Network, enable the Protocol column, and reload. You should see h2 for most requests and h3 once QUIC has been learned. If you only ever see http/1.1, the cause is almost always a missing TLS cipher or a TLS 1.2 minimum that your scanner report told you to set but that also removed the required AEAD suites.

Performance impact and when HTTP/3 is worth it

HTTP/3 pays off most for clients on lossy or high-latency links. Because QUIC replaces TCP’s head-of-line blocking with per-stream delivery, a single dropped packet no longer stalls every other request on the connection. On a clean low-latency LAN the gain is close to zero, which is why enabling it and measuring is the only honest approach.

ScenarioHTTP/2HTTP/3Verdict
Many small assets, low latencyExcellentEquivalentNo measurable gain
Mobile / lossy linksHead-of-line stallsPer-stream recoveryMeaningful gain
High-latency satellite/VPNHandshake cost per connection0-RTT resumptionLarge gain
Server CPU constrainedLower costHigher per-packet costKeep HTTP/2

Common failure modes

SymptomLikely causeFix
Only http/1.1 negotiatedTLS 1.2 ciphers trimmed below AEAD setRe-add ECDHE+AESGCM suites
h2 works, h3 neverUDP 443 blocked or provider filters UDPOpen UDP 443; otherwise accept h2
500 on HTTP/2 onlyLegacy ISAPI filter rejects streamsDisable HTTP/2 on that binding
Static files fine, app slowMultiplexing exposes app serializationProfile app, not IIS

A final note on sizing: HTTP/3 adds a little CPU per connection because encryption is per-datagram, and QUIC connections live in kernel-side structures that need memory headroom. On a modest instance, compare the resource ceiling against what the host actually provisions — the tradeoffs are laid out in our Windows VPS comparison.

Leave a Comment