How to check HTTP/3 support

Run curl --http3-only -s -o /dev/null -w '%{http_version}\n' https://www.cloudflare.com/. A build with ngtcp2 prints 3 when QUIC reached the server, and exits 7 when it did not. Confirm the build with curl --version first, because a build without ngtcp2 rejects the flag outright.

Checker offline. Follow the manual steps below, they give the same answer.

Why check this

Run this when a CDN or edge configuration changes, and before signing off a mobile performance story. HTTP/3 runs over QUIC on UDP 443, so a firewall rule that only opens TCP 443 removes it for everyone behind that firewall while the site keeps working. Nothing fails, nothing logs, and the connection-setup saving on a lossy mobile network quietly goes away. The check also separates a server that never offered HTTP/3 from a network that blocked it.

Prerequisites

Steps

  1. Step 1.

    Confirm the QUIC libraries are linked into your curl.

    curl --version | grep -o -E 'ngtcp2/[0-9.]+|nghttp3/[0-9.]+'
    
    ngtcp2/1.25.0
    nghttp3/1.18.0
  2. Step 2.

    Force QUIC and read the protocol version that came back.

    curl -s -o /dev/null --http3-only -w '%{http_version} %{num_connects}\n' https://www.cloudflare.com/; echo "exit=$?"
    
    3 1
    exit=0

    --http3-only refuses to fall back to TCP, so a 3 here is proof rather than a guess.

  3. Step 3.

    Point the same command at a host that serves no HTTP/3 and record the failure shape.

    curl -s -o /dev/null --http3-only --max-time 10 -w '%{http_version}\n' https://example.com/; echo "exit=$?"
    
    0
    exit=7

    Exit 7 is "failed to connect". A version of 0 means no response arrived at all, which is what a blocked UDP port also looks like.

  4. Step 4.

    Read the advertisement a browser would use, which arrives over TCP.

    curl -sI https://www.cloudflare.com/ | grep -i '^alt-svc'
    
    alt-svc: h3=":443"; ma=86400
  5. Step 5.

    Make a first request with an empty alt-svc cache, the way a browser starts.

    curl -s -o /dev/null --alt-svc h3.txt -w '%{http_version}\n' https://www.cloudflare.com/
    
    2

    Nothing is cached yet, so this request goes over TCP even though the server serves HTTP/3.

  6. Step 6.

    Repeat the identical command and watch the cached advertisement take effect.

    curl -s -o /dev/null --alt-svc h3.txt -w '%{http_version}\n' https://www.cloudflare.com/
    
    3

    Same command, different protocol. h3.txt now holds the entry curl read before opening the connection.

How to read the result

| What you see | What it means | What to do | | --- | --- | --- | | 3 with --http3-only | QUIC reached the server and answered | Nothing. Record the value with the curl version next to it. | | exit=7 and version 0 | Nothing answered on UDP 443 | Separate server from network: rerun from another network before filing against the server. | | option --http3-only: the installed libcurl version doesn't support this | Your build has no ngtcp2 | Install a QUIC-capable build. The server has not been tested. | | alt-svc: h3=":443" present but --http3-only fails | The server advertises HTTP/3 that your path cannot reach | A middlebox or firewall drops UDP 443. Check egress rules first. | | No alt-svc header at all | No browser will ever try HTTP/3 here | Enable the advertisement on the edge; direct QUIC support alone changes nothing for browsers. |

Common mistakes

Sign: curl accepts --http2 and prints 1.1, so the same tester assumes --http3 will report honestly too.Cause: Two different failure modes in one tool. Verified here on 2026-09-11: curl 8.1.2 Schannel answered --http2 with 1.1 and exit 0, while the same build rejected --http3-only with 'the installed libcurl version doesn't support this' and exit 2. The silent one is the dangerous one, so check curl --version rather than reading exit codes.
Sign: The server does HTTP/3 in a browser but --http3-only times out from the build machine.Cause: QUIC uses UDP 443 and most corporate egress rules allow TCP 443 only. The browser fell back to TCP without telling anyone. Test from a second network before concluding anything about the server.
Sign: A single curl run without --alt-svc reports 2 and the tester concludes HTTP/3 is off.Cause: Curl does not upgrade on its own the way a browser does. Without a cached alt-svc entry or an explicit --http3 flag it stays on TCP. Steps 5 and 6 show the same host answering 2 then 3 across two identical requests.

Thresholds

ma=86400

The ma field is the freshness lifetime of the advertisement in seconds. Cloudflare sent 86400 on 2026-09-11, so a browser keeps trying QUIC for 24 hours after one TCP request.

Source: https://www.rfc-editor.org/rfc/rfc7838#section-3.1

What to check next

FAQ

Why is my browser not using HTTP/3?

It uses HTTP/3 only after it has seen alt-svc on a normal TCP response and cached it. A first visit is always TCP. If the header is absent, or UDP 443 is blocked on your network, the browser stays on HTTP/2 without reporting anything.

How do I check if QUIC is enabled?

Step 2 is the test. QUIC is the transport under HTTP/3, so a %{http_version} of 3 with --http3-only means a QUIC handshake completed. There is no separate QUIC-only check worth running for a web service.

How do I check HTTP/3 with curl when my build has no ngtcp2?

You cannot. The flag is rejected by the option parser before any request is made. Read alt-svc with step 4 to learn what the server advertises, then run step 2 elsewhere to confirm it answers.

Does HTTP/3 replace HTTP/2 on the server?

No. A host keeps answering HTTP/2 on TCP 443 and advertises HTTP/3 alongside it. Both paths need testing, because a config change can break one and leave the other working.

Verified

Verified by Maks Vernycurl 8.21.0curl 8.1.2 Schannel

Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.

intermediate6 minpublished updated Maks Verny