The SSL handshake is failing because the client and server can’t agree on a common set of cryptographic algorithms or parameters necessary to establish a secure connection.
Common Causes and Fixes for SSL Alert Number 40 (Handshake Failure)
This error means the SSL/TLS handshake between your client and the server has collapsed. It’s not just a simple timeout; it’s a fundamental disagreement on how to secure the communication channel, usually stemming from incompatible cipher suites, protocol versions, or certificate issues.
-
Cipher Suite Mismatch: The most frequent culprit. Your client (e.g., web browser,
curl) and the server support different sets of encryption algorithms (cipher suites). The handshake fails because they can’t find a common suite they both agree to use.- Diagnosis: On the server-side (if you control it, e.g., Apache, Nginx), check your SSL configuration file. For example, in Nginx, look for the
ssl_ciphersdirective.
You can test your server’s supported cipher suites using# Example Nginx ssl_ciphers directive ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256; ssl_prefer_server_ciphers on;openssl s_client:
Or, more targeted:openssl s_client -connect your_domain.com:443 -cipher ALL
On the client-side, you might need to specify a cipher suite if your client is old or has very restrictive defaults. Foropenssl s_client -connect your_domain.com:443 -tls1_2 -cipher ECDHE-RSA-AES256-GCM-SHA384curl:curl -v --ciphers ECDHE-RSA-AES256-GCM-SHA384 https://your_domain.com - Fix: Update your server’s
ssl_ciphersdirective to include more modern and widely supported cipher suites. Ensure you’re not excluding all common ones. A good starting point for Nginx/Apache is a modern, recommended list that includes AES-GCM and ECDHE, such as:
Restart your web server after changing the configuration. This works because by adding common, strong cipher suites, you increase the probability that the client and server will find at least one mutually supported algorithm to use for encryption.ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256
- Diagnosis: On the server-side (if you control it, e.g., Apache, Nginx), check your SSL configuration file. For example, in Nginx, look for the
-
Incompatible TLS/SSL Protocol Versions: The client and server are trying to use different versions of the TLS/SSL protocol (e.g., client wants TLS 1.3, server only supports TLS 1.2 or older).
- Diagnosis: Check your server’s SSL configuration for directives like
ssl_protocols(Nginx) orSSLProtocol(Apache).
You can test supported protocols with# Example Nginx ssl_protocols directive ssl_protocols TLSv1.2 TLSv1.3;openssl s_client:
Foropenssl s_client -connect your_domain.com:443 -tls1 openssl s_client -connect your_domain.com:443 -tls1_1 openssl s_client -connect your_domain.com:443 -tls1_2 openssl s_client -connect your_domain.com:443 -tls1_3curl, you can force a protocol version:curl -v --tlsv1.2 https://your_domain.com curl -v --tlsv1.3 https://your_domain.com - Fix: Configure your server to support a range of protocols that are both secure and widely compatible. For most modern deployments, enabling TLS 1.2 and TLS 1.3 is sufficient.
Restart your web server. This works because by enabling specific protocol versions, you ensure that the client has a viable option to connect using a secure and understood version of the protocol.ssl_protocols TLSv1.2 TLSv1.3;
- Diagnosis: Check your server’s SSL configuration for directives like
-
Expired or Invalid Server Certificate: The server’s SSL certificate has expired, or it’s not trusted by the client’s operating system or browser.
- Diagnosis:
- Browser: Look at the certificate details in your browser. Most browsers will explicitly warn you about expired certificates.
openssl:
This will show theopenssl x509 -in your_certificate.crt -noout -datesnotBeforeandnotAfterdates.curl:
Look for output related to certificate verification.curl -v https://your_domain.com
- Fix: Renew your SSL certificate. If you’re using a service like Let’s Encrypt, ensure your renewal process is working correctly. If you’re using a commercial certificate, purchase a new one before the old one expires. Install the new certificate and its intermediate chain correctly on your server. This works because the handshake requires a valid, trusted certificate from the server; an expired or untrusted one immediately breaks the trust establishment phase.
- Diagnosis:
-
Incorrect Certificate Chain: The server is not sending the full certificate chain (intermediate certificates) needed for the client to verify the server’s certificate against a trusted root CA.
- Diagnosis: Use online SSL checkers like SSL Labs’ SSL Test (https://www.ssllabs.com/ssltest/) or
openssl s_client:
Examine the output. If you see only one certificate (the server’s end-entity certificate) and not the intermediate(s) leading to a known CA, this is the problem.openssl s_client -connect your_domain.com:443 -showcerts - Fix: Concatenate your server certificate with any required intermediate certificates in the correct order. The server certificate should be first, followed by its intermediate(s). For Nginx, this is typically done in a single file specified by
ssl_certificate:
Restart your web server. This works because clients need the full chain to trace the server’s certificate back to a root certificate authority (CA) that they inherently trust; without the intermediates, the verification path is broken.# In your ssl_certificate file: -----BEGIN CERTIFICATE----- ... your server certificate ... -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- ... your intermediate certificate 1 ... -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- ... your intermediate certificate 2 (if any) ... -----END CERTIFICATE-----
- Diagnosis: Use online SSL checkers like SSL Labs’ SSL Test (https://www.ssllabs.com/ssltest/) or
-
Client-Side Firewall or Proxy Interference: A firewall or proxy between the client and server is inspecting or blocking SSL traffic, or it’s presenting its own untrusted certificate.
- Diagnosis: Try connecting from a different network or machine. If it works, the issue is likely local to your network. Check proxy settings on the client. If you’re behind a corporate firewall, it might be performing SSL inspection.
- Fix: If a proxy is involved, ensure its SSL/TLS configuration is compatible or bypass it for the connection. If a firewall is performing SSL inspection, you may need to configure an exception for the specific domain or IP address, or ensure the firewall’s root certificate is trusted by the client. This works because the handshake might be intercepted and terminated by an intermediary device, or the intermediary might be presenting a certificate that the client doesn’t trust, causing the handshake to fail.
-
Server Configuration Issues (e.g.,
ssl_session_ticketsorssl_session_cache): Less common, but misconfiguration of SSL session resumption can sometimes lead to handshake failures, especially after server restarts or in load-balanced environments.- Diagnosis: Temporarily disable session resumption features on the server (e.g.,
ssl_session_tickets off;in Nginx) and see if the handshake succeeds. - Fix: Re-enable session resumption with a correctly configured cache or ticket key management system. Ensure session ticket keys are shared across all servers in a load-balanced setup if using
ssl_session_tickets. This works because while session resumption speeds up connections, improper handling of session data can lead to state inconsistencies that break subsequent handshakes.
- Diagnosis: Temporarily disable session resumption features on the server (e.g.,
After fixing these, the next most likely error you’ll encounter is an SSL Alert Number 10: No shared cipher, if you’ve only partially resolved the cipher suite issue and the client/server still can’t find a common ground, or potentially a Certificate Unknown error if there’s an issue with certificate authority trust.