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
- A curl build with QUIC.
curl --versionhas to name bothngtcp2andnghttp3. See the curl HTTP/3 documentation. - Outbound UDP 443 from this machine. Corporate networks block it more often than they block TCP.
- The hostname as the browser requests it, since the
alt-svcadvertisement is issued per host.
Steps
- 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 - 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-onlyrefuses to fall back to TCP, so a3here is proof rather than a guess. - 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=7Exit 7 is "failed to connect". A version of
0means no response arrived at all, which is what a blocked UDP port also looks like. - 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 - 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/2Nothing is cached yet, so this request goes over TCP even though the server serves HTTP/3.
- 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/3Same command, different protocol.
h3.txtnow 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
Thresholds
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.
What to check next
- How to check if a website uses HTTP/2: the protocol every HTTP/3 host still answers on first contact.
- How to check alt-svc header: the field-by-field read of the advertisement used in step 4.
- How to check if keep-alive is enabled: QUIC connection reuse is measured the same way as TCP reuse.
- How to check DNS lookup time: the other half of connection setup, and an HTTPS record can point at QUIC directly.
- Http2 test: runs the ALPN and QUIC probe from a host with UDP 443 open.
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.
Related on this site
- Checker: http2-http3 ALPN negotiation for h2, Alt-Svc and direct h3, TLS version
- All performance and delivery checks
intermediate6 minpublished updated Maks Verny