curl "(35) SSL connect error" in CI
Error 35 means curl could not complete the TLS handshake at all, before any certificate check. It points at the transport layer: an incompatible TLS version or cipher, a handshake cut short by a proxy or firewall, or an OpenSSL that cannot negotiate with the server. It is distinct from error 60, which is a certificate-trust failure after a successful handshake.
What this error means
curl exits with "curl: (35) SSL connect error" or "curl: (35) OpenSSL/... error". The connection reaches the host but never establishes a secure channel.
curl: (35) OpenSSL/3.0.2: error:0A000410:SSL routines::sslv3 alert handshake failureCommon causes
A TLS version or cipher mismatch
The server requires a TLS version or cipher the runner's OpenSSL will not offer (for example TLS 1.0 disabled, or a legacy cipher), so the handshake aborts.
A proxy or firewall interrupts the handshake
A TLS-inspecting proxy or egress firewall closes or corrupts the handshake mid-negotiation, which curl reports as a connect error.
How to fix it
Inspect the handshake with verbose output
- Re-run curl with
-vto see which TLS version and cipher were negotiated before the failure. - Confirm the server's minimum TLS version against what the runner OpenSSL supports.
- If a proxy is in the path, verify it is not terminating or blocking the handshake.
curl -v https://example.com 2>&1 | grep -Ei 'tls|ssl|cipher|alert'Align the TLS version with the server
If the server needs a specific TLS version, request it explicitly, or update the runner OpenSSL so it can negotiate a modern one.
# force TLS 1.2 for a server that rejects newer negotiation
curl --tlsv1.2 --tls-max 1.2 https://legacy.example.comHow to prevent it
- Keep the runner OpenSSL and curl current so modern TLS negotiates cleanly.
- Confirm the endpoint's supported TLS versions before pinning one in CI.
- Rule out a proxy or firewall that resets the handshake before blaming certificates.