The command
curl -v --tlsv1.2 https://httpbin.org/get
What the flags do
| Flag | What it does |
|---|---|
--tlsv1.2 / --tlsv1.3 | The lowest TLS version curl will accept, not an exact one. |
--tls-max 1.2 | The highest version curl will offer. |
--ciphers list | Restrict the cipher suites for TLS 1.2 and below. TLS 1.3 suites use --tls13-ciphers. |
-w "%{ssl_verify_result}" | Print the certificate check result; 0 means it passed. |
--cert-status | Require a valid stapled OCSP response from the server. |
Reading what was negotiated
With -v, the lines beginning with an asterisk narrate the handshake. One reports the agreed protocol version and cipher suite, another whether the server accepted HTTP/2 through ALPN, and the certificate details follow. For a script, write-out variables give single values instead: the verification result, the HTTP version that was chosen, and time_appconnect, the number of seconds until the handshake finished.
curl -v -o /dev/null https://httpbin.org/get 2>&1 | grep -E "SSL connection|ALPN"
curl -s -o /dev/null https://httpbin.org/get \
-w "verify: %{ssl_verify_result}\nhttp: %{http_version}\ntls done after %{time_appconnect}s\n"
Testing one protocol version
The version flags set a floor, so --tlsv1.2 happily connects with 1.3. To ask "does this server still accept exactly 1.2?", set the ceiling to the same value. To ask whether 1.3 is available, require it with --tlsv1.3 and nothing else. When the two sides have no version in common the handshake fails and curl exits with code 35, which is the answer to the question rather than a malfunction.
# exactly TLS 1.2: floor and ceiling set to the same version
curl -sS -o /dev/null --tlsv1.2 --tls-max 1.2 -w "%{http_code}\n" https://httpbin.org/get
Why the same command differs between machines
Curl does not implement TLS; it delegates to a library chosen when it was built, and the first line of curl --version names it. OpenSSL is usual on Linux, the curl bundled with Windows uses Schannel, and macOS ships its own. They differ in where trusted authorities come from (a bundle file or the operating system's store), in how cipher suites are named, and in which options they support at all. A command that passes on a server and fails on a laptop is very often this, not the network.
curl --version | head -n 1
# OpenSSL-style cipher name; other TLS libraries spell it differently
curl -sS -o /dev/null --tls-max 1.2 --ciphers ECDHE-RSA-AES128-GCM-SHA256 \
-w "%{http_code}\n" https://example.com/
Common mistakes
--tlsv1.2does not mean "only 1.2". It is a minimum. Add--tls-max 1.2to pin the version.- Cipher names are library-specific. A name the local TLS library does not recognise ends the command with exit code 59.
- The scheme decides the protocol, not the port. An
https://URL aimed at a plain-HTTP port fails with a handshake error that mentions a wrong version number.
Related curl examples
Curl HTTPS Request Example
An https:// URL is all curl needs to use TLS, and it verifies the server's certificate by default.
Curl -k Flag Example
-k is short for --insecure.
Curl Ignore Certificate Checks Example
-k tells curl to proceed even though it cannot verify who it is talking to.
Convert Curl to a Raw HTTP Request
Every curl command turns into a few lines of text sent over a socket.
SSL Checker
Check a certificate from outside your network: trust, host name and expiry.
All Curl Examples
49 worked examples, grouped by what you are trying to do.
References
- curl man page: --tlsv1.2 — Setting the minimum TLS version.
- curl man page: --tls-max — Setting the maximum TLS version.
- curl: SSL certificate verification — How curl finds its CA store and what to do when verification fails.
These links leave api-tester.com, which is independent of the projects they point to.
FAQ
How do I send an SSL request with curl?
Use a URL that starts with https://. Curl performs the TLS handshake, verifies the certificate and encrypts the request automatically. SSL is the older name for TLS.
How do I force curl to use a specific TLS version?
Set the minimum with --tlsv1.2 or --tlsv1.3 and the maximum with --tls-max. Using both with the same version forces exactly that version.
How do I see which TLS version and cipher curl used?
Run the request with -v. The handshake lines report the negotiated protocol version and cipher suite, followed by the server certificate details.