h2load — HTTP/2 Load Testing on the Command Line

Practical guide to h2load — HTTP/2 and HTTP/1.1 load tests with concurrent streams, TLS, rate control and experimental HTTP/3 (QUIC).

h2load is the benchmarking and load-testing tool from the nghttp2 project: it measures server throughput and latency under HTTP/2 and HTTP/1.1 load, using real concurrent streams just as a browser would send them. A handful of flags let you fire a hundred thousand requests from a hundred parallel clients, control the connection rate, switch between TLS and cleartext, and read the results straight from the compact summary output.

Basic Usage

h2load <url> — Send a single request to the given URL (default: 1 request, 1 client).

h2load https://localhost:8443/

h2load -n <requests> -c <clients> -m <streams> <url> — Run a benchmark with N total requests, C concurrent clients, and M max concurrent streams per session.

h2load -n100000 -c100 -m10 https://localhost:8443/

h2load -n <requests> -c <clients> -t <threads> <url> — Use multiple native threads. Useful when the benchmark client itself becomes a bottleneck.

h2load -n100000 -c100 -t4 https://localhost:8443/

h2load -n <requests> -c <clients> -m <streams> -t <threads> <url> — Full benchmark with threads, clients, and concurrent streams.

h2load -n1000000 -c200 -m50 -t8 https://localhost:8443/

Duration-Based Benchmarking

h2load -c <clients> -m <streams> -D <duration> <url> — Run for a fixed duration instead of a fixed number of requests. The -n option is ignored.

h2load -c100 -m10 -D 30s https://localhost:8443/

h2load -c <clients> -m <streams> -D <duration> --warm-up-time=<duration> <url> — Run with a warm-up period before actual measurement begins. Requires -D.

h2load -c100 -m100 -D 60s --warm-up-time=5s https://localhost:8443/

Rate Control

h2load -n <requests> -c <clients> -r <rate> <url> — Create connections at a fixed rate per second. Distributed evenly among threads. Mutually exclusive with -D.

h2load -n10000 -c100 -r4 -t2 https://localhost:8443/

h2load -n <requests> -c <clients> -r <rate> --rate-period=<duration> <url> — Create connections at a fixed rate per custom time period.

h2load -n10000 -c100 -r10 --rate-period=500ms https://localhost:8443/

h2load -n <requests> -c <clients> --rps=<N> <url> — Limit requests per second for each client. Mutually exclusive with --timing-script-file.

h2load -n10000 -c10 --rps=100 https://localhost:8443/

Protocol Selection

h2load --h1 <url> — Force HTTP/1.1 for both TLS and cleartext connections.

h2load -n1000 -c10 --h1 https://localhost:8443/

h2load -p h2c <url> — Use HTTP/2 cleartext (h2c) for non-TLS connections. This is the default.

h2load -n1000 -c10 -p h2c http://localhost:8080/

h2load -p http/1.1 <url> — Use HTTP/1.1 for cleartext connections.

h2load -n1000 -c10 -p http/1.1 http://localhost:8080/

h2load --alpn-list=<protocols> <url> — Set ALPN protocol list for TLS negotiation in preference order.

h2load -n1000 -c10 --alpn-list=h2,http/1.1 https://localhost:8443/

h2load --alpn-list=h3 <url> — Use HTTP/3 (QUIC). Experimental, requires h2load built with QUIC support.

h2load -n1000 -c10 --alpn-list=h3 https://localhost:443/

Headers & POST Data

h2load -H '<header>' <url> — Add or override an HTTP header. Can be specified multiple times.

h2load -n1000 -c10 -H 'Authorization: Bearer token123' https://localhost:8443/api

h2load -H '<h1>' -H '<h2>' <url> — Add multiple custom headers.

h2load -n1000 -c10 -H 'Accept: application/json' -H 'X-API-Key: abc123' https://localhost:8443/api

h2load -d <path> <url> — POST file contents to the server. Changes the request method to POST.

h2load -n1000 -c10 -d /tmp/payload.json -H 'Content-Type: application/json' https://localhost:8443/api

URI Input & Scripting

h2load <url1> <url2> <url3> — Benchmark multiple URIs in round-robin order. Only the first URI's scheme, host, and port are used.

h2load -n10000 -c50 https://localhost:8443/ https://localhost:8443/api https://localhost:8443/health

h2load -i <file> <url> — Read URIs from a file (one per line). Use - for stdin. Disables command-line URIs.

h2load -n10000 -c50 -i urls.txt https://localhost:8443/

h2load --timing-script-file=<file> — Replay timed request scripts. Each line: millisecond_offsetURI. With -n, requests become per-client.

h2load -c10 --timing-script-file=script.txt

h2load -B <base_uri> -i <file> — Override scheme, host, and port for all URIs from input file.

h2load -n10000 -c50 -B https://staging.example.com -i urls.txt

h2load -B unix:<path> <url> — Connect via UNIX domain socket.

h2load -n1000 -c10 -B unix:/tmp/nghttpx.sock http://localhost/

Connection & Timeout

h2load -T <duration> <url> — Set maximum connection active timeout regardless of activity.

h2load -n1000 -c10 -T 30s https://localhost:8443/

h2load -N <duration> <url> — Set maximum connection inactivity timeout.

h2load -n1000 -c10 -N 10s https://localhost:8443/

h2load --connect-to=<host>:<port> <url> — Connect to a different host:port than specified in the URI.

h2load -n1000 --connect-to=127.0.0.1:8443 https://example.com/

HTTP/2 Flow Control

h2load -w <bits> -W <bits> <url> — Set stream-level (-w) and connection-level (-W) initial window size as (2^N)-1 bytes. Default: 30 (very large).

h2load -n100000 -c100 -m10 -w16 -W16 https://localhost:8443/

h2load -f <size> <url> — Set the maximum HTTP/2 frame size the local endpoint is willing to receive.

h2load -n10000 -c50 -f 32K https://localhost:8443/

h2load --header-table-size=<size> <url> — Set HPACK decoder header table size.

h2load -n10000 -c50 --header-table-size=8K https://localhost:8443/

h2load --encoder-header-table-size=<size> <url> — Set HPACK encoder header table size.

h2load -n10000 -c50 --encoder-header-table-size=8K https://localhost:8443/

TLS Configuration

h2load --ciphers=<suite> <url> — Set allowed cipher list for TLSv1.2 or earlier (OpenSSL format).

h2load -n1000 -c10 --ciphers=ECDHE-RSA-AES128-GCM-SHA256 https://localhost:8443/

h2load --tls13-ciphers=<suite> <url> — Set allowed cipher list for TLSv1.3 (OpenSSL format).

h2load -n1000 -c10 --tls13-ciphers=TLS_AES_256_GCM_SHA384 https://localhost:8443/

h2load --groups=<groups> <url> — Set supported TLS groups (key exchange).

h2load -n1000 -c10 --groups=X25519:P-256 https://localhost:8443/

h2load --sni=<dnsname> <url> — Send a custom DNS name in TLS SNI, overriding the host from the URI.

h2load -n1000 --sni=example.com https://127.0.0.1:8443/

h2load --ktls <url> — Enable kernel TLS (kTLS) for potentially improved performance.

h2load -n100000 -c100 --ktls https://localhost:8443/

Logging & Output

h2load -v <url> — Enable verbose debug output.

h2load -v -n10 -c1 https://localhost:8443/

h2load --log-file=<path> <url> — Write per-request log (tab-separated: start time in µs, HTTP status, response time in µs). Status -1 for failed streams.

h2load -n10000 -c50 --log-file=/tmp/h2load.log https://localhost:8443/

h2load --qlog-file-base=<path> <url> — Enable qlog output for QUIC connections. Files are named base.M.N.sqlog (M=worker, N=client).

h2load -n1000 -c10 --alpn-list=h3 --qlog-file-base=/tmp/qlog https://localhost:443/

Common Patterns

h2load -n100000 -c100 -m10 <url> — Standard HTTP/2 benchmark: 100K requests, 100 clients, 10 concurrent streams.

h2load -n100000 -c100 -m10 https://localhost:8443/

h2load -c100 -m100 -D 60s --warm-up-time=5s <url> — Duration-based test with warm-up phase for stable measurements.

h2load -c100 -m100 -D 60s --warm-up-time=5s https://localhost:8443/

h2load -n10000 -c10 --h1 <url> — Compare HTTP/1.1 performance against HTTP/2 baseline.

h2load -n10000 -c10 --h1 https://localhost:8443/

h2load -n100000 -c100 -m10 -w16 -W16 <url> — Benchmark with HTTP/2 spec-default flow control windows (64K) instead of the large defaults.

h2load -n100000 -c100 -m10 -w16 -W16 https://localhost:8443/

for c in 10 50 100 500; do echo "--- $c clients ---"; h2load -n10000 -c$c -m10 <url>; done — Progressive load test at increasing concurrency levels.

for c in 10 50 100 500; do echo "--- $c clients ---"; h2load -n10000 -c$c -m10 https://localhost:8443/; done

h2load -c1 -m1 -n1 -v <url> — Single request with verbose output for debugging connection and protocol negotiation.

h2load -c1 -m1 -n1 -v https://localhost:8443/

Unit Conventions

h2load -D 30s / -D 1m / -D 500ms — Duration units: s=seconds, m=minutes, h=hours, ms=milliseconds. Default (no unit) is seconds.

h2load -f 16K / -f 1M / -f 1G — Size units: K=1024, M=1024², G=1024³. Used for frame size, header table size, and UDP payload size.

Conclusion

h2load is the go-to tool when you need reliable HTTP/2 performance numbers: the combination of concurrent streams, threads, and fine-grained TLS control models real browser load far better than classic tools. Start with the standard profile (-n100000 -c100 -m10) and tune clients and streams until you find your server's ceiling.

Further Reading

  • ab – classic Apache benchmark tool for quick HTTP load tests
  • wrk – modern HTTP benchmark with Lua scripting support
  • siege – load and stress testing for web servers