What it means: curl reached the server, but the TLS handshake failed before any HTTP was sent.
curl -v and note the last TLS stepopenssl s_clientFree online tool — SSL certificate checker: instant results, no signup.
Runs a full TLS check: handshake, protocol versions, certificate chain, trust and expiry.
Exit code 35 is CURLE_SSL_CONNECT_ERROR. The libcurl documentation is blunt about it: «A problem occurred somewhere in the SSL/TLS handshake. You really want the error buffer and read the message there as it pinpoints the problem slightly more.» The code only says «the handshake failed»; the text after it says why.
With the OpenSSL backend that text is OpenSSL's error string, for example TLS connect error: error:0A000410:SSL routines::sslv3 alert handshake failure. When OpenSSL has no reason to give, because the socket simply closed, curl prints OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to example.com:443 (lib/vtls/openssl.c). On Windows builds using Schannel the text starts with schannel: next InitializeSecurityContext failed: followed by a Windows status.
A rejected certificate is a different exit code. When the handshake completes but the chain or name does not verify, curl returns 60 (CURLE_PEER_FAILED_VERIFICATION) with SSL certificate problem: .... Exit 35 happens earlier: the two sides never agreed on a connection at all.
| Text after the code | What happened | Typical fix |
|---|---|---|
sslv3 alert handshake failure (OpenSSL 3.0) or ssl/tls alert handshake failure (3.2+), code 0A000410 | The server sent a handshake_failure alert: no shared cipher or version, or it needs SNI it did not get | Connect by hostname, enable TLS 1.2/1.3 and modern ciphers on the server |
tlsv1 alert protocol version | The server rejects every TLS version the client offered | Server: enable TLS 1.2 and 1.3. Old client: upgrade it |
SSL_ERROR_SYSCALL or unexpected eof while reading | The connection was closed or reset during the handshake | Look for a firewall, DPI box, proxy or crashing TLS terminator |
wrong version number | The other end is not speaking TLS on that port | Use the right port or scheme; check proxy settings |
| Schannel revocation status | Windows could not reach the CRL or OCSP server | Open access to the CA's revocation URLs |
The OpenSSL wording changed between releases: OpenSSL 3.0 prints «sslv3 alert handshake failure» while 3.2 and later print «ssl/tls alert handshake failure» for the same reason code 1040 (crypto/err/openssl.txt). Search logs by the hex code 0A000410 to catch both.
Most error 35 reports after an OS upgrade are version or cipher mismatches. OpenSSL 3 refuses TLS 1.0 and 1.1 at its default security level, so a client that worked against a legacy appliance stops working after the upgrade while browsers were already refusing it. The fix belongs on the server: TLS 1.2 or 1.3 with ECDHE ciphers. As a short diagnostic only, you can check whether an old protocol is the reason by testing it explicitly; do not ship such an override.
When the error appears only on one network (a corporate LAN, a hotel, a CI runner) and the same command works elsewhere, something in the path is interfering: a proxy that resets TLS to hosts it does not like, or a filter keyed on the SNI host name. SSL_ERROR_SYSCALL with zero bytes read is the usual signature. If you must go through an HTTPS-inspecting proxy, configure it with -x rather than letting it intercept transparently.
A server that requires a client certificate also stops TLS 1.2 handshakes with an alert. Under TLS 1.3 curl reports the missing certificate separately, as TLS cert problem: with exit code 58 (CURLE_SSL_CLIENTCERT).
curl -v https://example.com/ prints each TLS step (Client hello, Server hello...). If nothing comes back after the client hello, the server or a middlebox closed the connection.curl -V shows OpenSSL/3.x, Schannel or another backend. The reason strings differ between them.openssl s_client -connect example.com:443 -servername example.com -tls1_3 -brief </dev/null
openssl s_client -connect example.com:443 -servername example.com -tls1_2 -brief </dev/null
openssl s_client -connect example.com:443 -noservername -brief </dev/nullIf only the last one fails, the server needs SNI and your client is not sending it, typically because it connects to an IP address.nmap --script ssl-enum-ciphers -p 443 example.com. No TLS 1.2 or 1.3 entries means the server is the problem.nginx -T | grep -E 'ssl_protocols|ssl_ciphers' and enable ssl_protocols TLSv1.2 TLSv1.3;. Look in the error log for SSL_do_handshake() failed lines with the same OpenSSL reason.--ssl-revoke-best-effort ignores revocation checks only when the distribution points are missing or offline; --ssl-no-revoke turns checks off entirely and loosens security.curl -sS -o /dev/null -w '%{http_code} %{ssl_verify_result}\n' https://example.com/
# 200 0
openssl s_client -connect example.com:443 -servername example.com -brief </dev/null
# Protocol version: TLSv1.3Test from the network that failed. To see which protocol versions and certificate the server presents from outside, run the SSL/TLS checker.
SSL/TLS is the encryption protocol that protects data between the browser and server. Our tool analyzes the certificate, chain of trust, TLS version, and knownvulnerabilities.
Issuer, validity period, signature algorithm, covered domains (SAN), and validation type (DV/OV/EV).
Full chain verification: from leaf certificate through intermediates to root CA.
Protocol version (TLS 1.2/1.3), cipher suites, Perfect Forward Secrecy (PFS) support.
Set up a monitor — get Telegram and email alerts 30/14/7 days before expiration.
SSL certificate monitoring
TLS config audit
HTTPS as ranking factor
customer trust
www and subdomains.Strict-Transport-Security header forces browsers to always use HTTPS.SSL certificate monitoring, check history and alerts 30 days before expiry.
Sign up freeError 35 means the TLS handshake itself failed, so no secure connection was set up. Error 60 means the handshake worked but the server certificate could not be verified.
No. -k only skips certificate verification, which happens after a successful handshake. A version, cipher or connection problem fails before verification is ever reached.
OpenSSL saw the connection end without a TLS alert, usually a reset or close from a firewall, proxy or a crashing server. Compare the result from another network to find out where it happens.
The new OpenSSL refuses old protocol versions and weak ciphers by default. The server still offers only those, so the handshake has no common ground; enable TLS 1.2 or 1.3 on the server.
Connecting by IP sends no SNI, and servers hosting several sites may refuse a handshake without it. Use the hostname, or with curl --resolve example.com:443:203.0.113.10 to pin the IP while keeping the name.
Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.