Curl SSL Request Example

Every https:// request curl makes is an SSL request in the everyday sense, although the protocol has been called TLS for a long time. This page is about steering and inspecting the handshake itself; certificates and trust have their own page.

Last updated . How this page is checked.

The command

curl -v --tlsv1.2 https://httpbin.org/get

What the flags do

FlagWhat it does
--tlsv1.2 / --tlsv1.3The lowest TLS version curl will accept, not an exact one.
--tls-max 1.2The highest version curl will offer.
--ciphers listRestrict 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-statusRequire 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.2 does not mean "only 1.2". It is a minimum. Add --tls-max 1.2 to 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

References

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.