curl is often the fastest way to isolate whether an SSL problem is genuinely server-side or specific to a particular client or browser — but only if you know how to read its specific error output rather than treating every SSL-related curl failure as the same generic problem.
Exit code 60: certificate verify failed
This is the most common SSL-related curl error, and it means curl couldn't build a trusted chain from the server's certificate to a root it trusts. Run with -v for verbose output, which shows exactly which certificates curl received and where the chain building failed:
curl -v https://yourdomain.com
If the verbose output shows curl only received one certificate (your leaf certificate, no intermediates), that confirms a server-side incomplete chain — the fix belongs on the server, not in your curl invocation. If curl received a full chain but still failed, check whether curl's own CA bundle is outdated (particularly relevant on older Linux distributions or systems with an infrequently updated CA bundle package).
Exit code 35: SSL connect error
This indicates the handshake itself failed, generally before certificate details were fully exchanged — commonly a protocol version or cipher suite mismatch between your curl installation and the server. Testing with an explicit TLS version flag helps isolate this:
curl -v --tlsv1.2 https://yourdomain.com
If specifying a TLS version explicitly resolves the connection, your curl installation's default negotiated version isn't compatible with what the server offers — worth checking whether your curl/OpenSSL version is significantly outdated, since older installations sometimes default to attempting deprecated protocol versions first.
Exit code 58: local certificate problem
This specifically relates to a client certificate you're providing (relevant for mutual TLS/mTLS connections) rather than the server's certificate — check that the client certificate and key files you're passing via --cert and --key are valid, correctly formatted, and that the key actually matches the certificate.
Using curl to isolate server-side versus client-side issues
One of curl's most useful troubleshooting properties is that it uses its own independent trust store and TLS implementation, separate from any browser — if a certificate works fine in a browser but fails in curl, that's a meaningful signal in itself, since it usually points to an incomplete chain that a browser's more forgiving intermediate caching is masking, exactly the scenario covered in our related "works in Chrome, fails in API client" guide.
Never reach for -k as a permanent fix
curl's -k / --insecure flag disables certificate verification entirely — useful for quickly confirming whether SSL verification specifically is the blocker during active debugging, but never appropriate as a permanent fix in a script, cron job, or production integration, since it removes the actual security property TLS is providing.
What curl's -v flag reveals that the base error message doesn't
Adding -v to any curl command shows the full handshake exchange, including exactly which certificate was presented, which CA curl attempted to validate it against, and at what specific step the failure occurred — considerably more diagnostic detail than curl's default, terse one-line error message alone provides.
How curl's own bundled CA list differs from your operating system's trust store
curl on some systems uses its own bundled CA certificate list (via a ca-bundle file) rather than the operating system's trust store — an outdated bundled CA list can cause curl to report a trust error even when the same certificate validates correctly in a browser using the OS's more current trust store.
Why reproducing a curl error with a minimal, isolated test case speeds up diagnosis
Stripping away every unnecessary flag and option, testing with a bare `curl -v https://domain.com`, isolates whether a specific flag or option in your original, more complex command is actually contributing to the error, rather than the underlying TLS connection itself being the problem.
What SSL_ERROR_SYSCALL specifically indicates versus a clean handshake rejection
SSL_ERROR_SYSCALL typically means the underlying network connection dropped unexpectedly during the handshake, rather than the handshake completing and being cleanly rejected — this points toward a network-level cause (a firewall silently dropping the connection, an unstable network path) rather than a certificate or configuration problem specifically.
How curl's --cacert flag lets you test against a specific, known trust bundle
Explicitly specifying a CA bundle file with --cacert lets you test whether a connection validates correctly against a known-good, current trust bundle, isolating whether curl's own default bundle is the actual source of a trust-related error versus a genuine problem with the server's certificate chain.
Why curl errors sometimes differ between command-line curl and a language's curl-based library
A language binding built on libcurl (PHP's cURL extension, Python's pycurl, and similar) can be compiled against a different OpenSSL or CA bundle version than your system's standalone curl binary, meaning the exact same URL can produce different results between the two — checking both independently helps isolate whether an issue is specific to one particular binding's configuration.
What SSL_ERROR_WANT_READ and similar non-fatal codes actually mean
Some error codes that look alarming at first glance, like WANT_READ or WANT_WRITE, actually indicate normal, expected non-blocking I/O behavior rather than a genuine failure — these are specifically relevant when curl or a library is used in non-blocking mode, and shouldn't be treated the same way as a genuine handshake rejection.
How curl's exit codes map to specific categories of failure
curl returns a specific numbered exit code for different failure categories (35 for a generic SSL connect error, 51 for a certificate verification failure, 60 for a CA-related trust failure, among others) — checking curl's exit code directly, in addition to the printed error message, gives a reliable, scriptable way to distinguish failure categories in automated tooling.
Why testing the same URL with curl, a browser, and OpenSSL together builds a complete picture
Running the identical URL through curl, a browser, and OpenSSL's s_client independently triangulates the actual problem — if only curl fails while the others succeed, the issue likely lies in curl's specific configuration or bundled trust data rather than the server itself.
A quick reference for the most common curl SSL error codes
Exit code 35 generally means a generic connect error, often protocol negotiation failure; 51 means the peer certificate failed validation against the hostname; 60 specifically means the CA certificate couldn't be verified; 58 means a problem with a locally supplied client certificate — checking this against curl's own documentation resolves ambiguity fast.
Why this diagnostic approach transfers directly to other command-line HTTP tools
The same layered approach, checking the specific error code, adding verbosity, testing with an explicit CA bundle, isolating with a minimal reproduction, applies just as well to wget, httpie, or any other command-line HTTP client — the underlying TLS concepts don't change based on which specific tool is making the connection.
-v) output map directly to distinct failure categories — read them before guessing, and use curl's independence from any browser's caching behavior to confirm whether a certificate issue is genuinely server-side.