How to Enable HTTP/2 in IIS on Windows Server 2025

HTTP/2 is the second major revision of the HTTP protocol, designed to address the performance bottlenecks inherent in HTTP/1.1 through features such as header compression (HPACK), request multiplexing over a single TCP connection, and binary framing. On Windows Server 2025 running IIS 10, HTTP/2 is enabled by default for HTTPS connections — but administrators still need to understand what prerequisites must be in place, how to verify that HTTP/2 is actually being negotiated, how to fine-tune server push behavior, and under what circumstances HTTP/2 should be disabled. This guide covers all of these scenarios, along with a forward-looking comparison to HTTP/3 (QUIC).

Prerequisites

  • Windows Server 2025 with IIS 10 (HTTP/2 is only supported on IIS 10 and later)
  • A valid SSL/TLS certificate bound to the site on port 443
  • TLS 1.2 or TLS 1.3 must be enabled (HTTP/2 requires TLS via the ALPN extension)
  • Client must support HTTP/2 (all modern browsers and recent versions of curl do)
  • Windows Server 2016 or later kernel (Windows Server 2025 satisfies this)
  • The site must use a standard IIS HTTPS binding — HTTP-only sites always negotiate HTTP/1.1

Step 1: Verify That HTTP/2 Is Active

Because IIS 10 on Windows Server 2025 enables HTTP/2 by default, the first step is to confirm it is actually being negotiated for your site. Use curl from a machine that has a modern version installed:

# Test whether the server negotiates HTTP/2
curl -I --http2 -s https://example.com/ | head -5

# Expected output for HTTP/2:
# HTTP/2 200
# content-type: text/html; charset=UTF-8
# ...

# Force HTTP/1.1 for comparison
curl -I --http1.1 -s https://example.com/ | head -3

In the browser, open DevTools → Network tab → right-click a column header → enable Protocol. Reload the page. Requests negotiated over HTTP/2 display h2 in the Protocol column.

Step 2: Check the Windows Registry HTTP/2 Setting

IIS delegates HTTP/2 negotiation to the Windows HTTP.sys kernel driver. The global on/off toggle lives in the Windows registry:

# Read the current HTTP/2 state
$regPath = "HKLM:SYSTEMCurrentControlSetServicesHTTPParameters"
$val = Get-ItemProperty -Path $regPath -Name "EnableHttp2Tls" -ErrorAction SilentlyContinue

if ($val -eq $null) {
  Write-Host "EnableHttp2Tls not set — HTTP/2 is ENABLED (default)."
} elseif ($val.EnableHttp2Tls -eq 0) {
  Write-Host "HTTP/2 is DISABLED via registry."
} else {
  Write-Host "HTTP/2 is ENABLED (EnableHttp2Tls = $($val.EnableHttp2Tls))."
}

The registry value EnableHttp2Tls is absent by default, which means HTTP/2 is on. Setting it to 0 disables HTTP/2 for all TLS sites on the server; setting it to 1 explicitly enables it (same as the default behavior).

Step 3: Ensure TLS 1.2 or TLS 1.3 Is Enabled

HTTP/2 relies on the ALPN (Application-Layer Protocol Negotiation) TLS extension, which requires TLS 1.2 as a minimum. Verify TLS version support in the registry:

# Verify TLS 1.2 is enabled (should be default on Server 2025)
$tls12Client = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Client"
$tls12Server = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Server"

foreach ($path in @($tls12Client, $tls12Server)) {
  if (-not (Test-Path $path)) {
    New-Item -Path $path -Force | Out-Null
  }
  Set-ItemProperty -Path $path -Name "Enabled"      -Value 1 -Type DWord
  Set-ItemProperty -Path $path -Name "DisabledByDefault" -Value 0 -Type DWord
}

Write-Host "TLS 1.2 enabled for both Client and Server."

On Windows Server 2025, TLS 1.3 is also supported natively in HTTP.sys and in Schannel and requires no additional configuration. Clients that support TLS 1.3 will negotiate it automatically, and HTTP/2 works over TLS 1.3 without any changes.

Step 4: Configure HTTP/2 Server Push via Link Headers

HTTP/2 server push allows IIS to proactively send resources to the client before the client requests them, reducing perceived load time. In IIS, push is implemented via Link: <url>; rel=preload response headers set in web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <!-- Push main stylesheet -->
        <add name="Link"
             value="</css/main.min.css>; rel=preload; as=style" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

When IIS detects a Link: rel=preload header in the response, it converts it into an HTTP/2 PUSH_PROMISE frame. For multiple assets, use multiple <add> elements or combine values with commas:

<add name="Link"
     value="</css/main.css>; rel=preload; as=style, </js/app.js>; rel=preload; as=script" />

Be selective with push — pushing too many resources can compete with resources the browser would cache from a previous visit, actually harming performance.

Step 5: Disable HTTP/2 If Needed

Some legacy clients, certain WebSocket implementations, or specific application frameworks may have compatibility issues with HTTP/2 multiplexing. To disable HTTP/2 globally on the server:

$regPath = "HKLM:SYSTEMCurrentControlSetServicesHTTPParameters"

# Disable HTTP/2 for all TLS sites
Set-ItemProperty -Path $regPath -Name "EnableHttp2Tls" -Value 0 -Type DWord

# Disable HTTP/2 for cleartext (HTTP) connections (already off by default)
Set-ItemProperty -Path $regPath -Name "EnableHttp2Cleartext" -Value 0 -Type DWord

Write-Host "HTTP/2 disabled. Restart required."

# A system restart or at minimum HTTP.sys reset is required
net stop http /y
net start w3svc

There is no per-site HTTP/2 toggle in IIS — the setting is server-wide via HTTP.sys. If you need to disable HTTP/2 for a single site while leaving it active for others, the common workaround is to place that site on a separate IIS instance or VM.

Step 6: Verify HTTP/2 Using IIS Logs

IIS does not log the protocol version in W3C logs by default, but you can use netsh or ETW tracing to inspect negotiated protocols. A simpler approach is to check via PowerShell using the HttpSys performance counters:

# View HTTP.sys connection statistics
netsh http show counters

# Use curl with verbose output to see ALPN negotiation
curl -v --http2 https://example.com/ 2>&1 | Select-String "ALPN|HTTP"

# Expected ALPN output:
# * ALPN: offers h2
# * ALPN: server accepted h2

Step 7: HTTP/2 vs HTTP/3 — What Comes Next

HTTP/3 replaces TCP with QUIC (UDP-based), eliminating head-of-line blocking at the transport layer — a limitation that even HTTP/2 multiplexing cannot fully resolve. Windows Server 2025 includes experimental support for HTTP/3 via msquic. To check and enable it:

# Check if HTTP/3 / QUIC is available
Get-WindowsFeature -Name "Internet-Information-Services"

# Enable QUIC transport (experimental on Server 2025)
# Set-ItemProperty HKLM:SYSTEMCurrentControlSetServicesHTTPParameters `
#   -Name EnableHttp3 -Value 1 -Type DWord

# Signal HTTP/3 availability via Alt-Svc response header
# Add in web.config:
# <add name="Alt-Svc" value="h3=":443"; ma=86400" />

Clients that receive the Alt-Svc: h3=":443" header and support HTTP/3 will attempt to upgrade subsequent connections to QUIC. HTTP/2 remains the production standard for IIS on Windows Server 2025, with HTTP/3 support maturing in future feature updates.

HTTP/2 in IIS on Windows Server 2025 is an immediate, zero-configuration performance improvement for any HTTPS-enabled site. The combination of request multiplexing, HPACK header compression, and optional server push can measurably reduce page load times — especially on high-latency connections — without any changes to your application code. Focus your verification efforts on confirming TLS 1.2 is properly configured, test the h2 negotiation with curl and browser DevTools, and use server push conservatively for critical above-the-fold resources. When HTTP/3 support matures in the IIS ecosystem, the groundwork you build with HTTP/2 today will translate directly to the next-generation protocol.