Using HTTP/3 with cURL is a direct way to confirm that an HTTPS endpoint can complete a request over QUIC before monitoring, edge routing, or client policy starts depending on that transport.
The --http3 option tells cURL to start with HTTP/3 and then fall back to HTTP/2 or HTTP/1.1 if the QUIC path does not come up quickly enough, while --http3-only removes that fallback and makes the request fail when HTTP/3 cannot be established. Both options require a cURL build whose Features: line includes HTTP3.
Packaged cURL builds do not all include QUIC support, and network devices can still block or delay UDP even when ordinary HTTPS works over TCP. Check the local build first, use --http3 to prove negotiated transport, and reserve --http3-only for strict checks where a timeout or connection failure is acceptable.
Related: How to use HTTP/2 in cURL
Related: How to debug HTTP requests with cURL
Steps to use HTTP/3 with cURL:
- Check the local cURL build for the HTTP3 feature before using protocol-specific flags.
$ curl --version curl 8.19.0 (aarch64-apple-darwin25.3.0) libcurl/8.19.0 OpenSSL/3.6.2 zlib/1.2.12 brotli/1.2.0 zstd/1.5.7 nghttp2/1.69.0 ngtcp2/1.22.1 nghttp3/1.15.0 Release-Date: 2026-03-11 Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt mqtts pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp ws wss Features: alt-svc AsynchDNS brotli HSTS HTTP2 HTTP3 HTTPS-proxy IPv6 Largefile libz SSL threadsafe UnixSockets zstd
Look for HTTP3 in the Features: line. Without it, --http3 and --http3-only fail immediately with an unsupported-option error.
- Send a header request with --http3 to let cURL try HTTP/3 first while still allowing an older protocol when necessary.
$ curl --http3 --silent --show-error --head https://portal-edge.example.test/ HTTP/3 200 content-length: 18426 server: edge-proxy content-type: text/html; charset=utf-8 cache-control: max-age=60 alt-svc: h3=":443"; ma=86400
A status line that starts with HTTP/3 confirms that the transfer completed over QUIC instead of a TCP fallback.
Related: How to send HEAD requests with cURL
- Print only the negotiated protocol number when a script or health check needs a single clean result.
$ curl --http3 --silent --show-error --output /dev/null --write-out '%{http_version}\n' https://portal-edge.example.test/ 3Output 3 confirms successful HTTP/3 negotiation, while 2 or 1.1 shows that the request finished over an earlier HTTP version instead.
- Inspect verbose output when the transport decision needs stronger proof than the response status line.
$ curl --http3 --verbose --silent --show-error --output /dev/null https://portal-edge.example.test/ * Host portal-edge.example.test:443 was resolved. * IPv4: 192.0.2.24, 192.0.2.25 * Trying 192.0.2.24:443... ##### snipped ##### * using HTTP/3 * [HTTP/3] [0] OPENED stream for https://portal-edge.example.test/ * [HTTP/3] [0] [:method: GET] * [HTTP/3] [0] [:authority: portal-edge.example.test] > GET / HTTP/3 < HTTP/3 200
The using HTTP/3 line and the HTTP/3 stream metadata provide stronger transport proof than the response status line alone.
- Test a host that does not currently complete HTTP/3 to see how --http3 falls back instead of failing.
$ curl --http3 --silent --show-error --output /dev/null --write-out '%{http_version}\n' https://legacy-www.example.test/ 2An output such as 2 or 1.1 means the request still succeeded, but the transfer did not stay on HTTP/3.
- Force strict transport with --http3-only after a normal --http3 request has already shown that the endpoint speaks HTTP/3.
$ curl --http3-only --silent --show-error --head https://portal-edge.example.test/ HTTP/3 200 content-length: 18426 server: edge-proxy content-type: text/html; charset=utf-8 cache-control: max-age=60 alt-svc: h3=":443"; ma=86400
Strict mode is appropriate when fallback would hide a broken QUIC path that should fail a check instead.
- Cap a strict-mode negative test with --max-time when the target or network path might never complete HTTP/3.
$ curl --http3-only --max-time 5 --silent --show-error --head https://legacy-www.example.test/ curl: (28) Connection timed out after 5001 milliseconds
--http3-only does not downgrade to HTTP/2 or HTTP/1.1, so unsupported targets and UDP-blocked paths fail the transfer instead of silently succeeding over TCP.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
