Introduction
SSL/TLS handshake failures are a common roadblock for developers, engineers, and DevOps teams. A broken handshake means encrypted traffic can’t be established, leading to service outages and frustrated users. This guide walks you through the most frequent causes and provides concrete, reproducible steps to fix them.
1. Verify the Certificate Chain
A missing intermediate or an expired root certificate is the #1 culprit.
openssl s_client -connect example.com:443 -showcerts -servername example.com
Inspect the output:
- The leaf certificate should be followed by all intermediate certificates.
- Look for
Verify return code: 0 (ok). Anything else signals a chain problem.
Fix
If an intermediate is missing, concatenate it with your leaf cert and restart the service:
cat leaf.crt intermediate.crt > fullchain.crt
# for Nginx
sudo cp fullchain.crt /etc/nginx/ssl/example.com.crt
sudo systemctl reload nginx
2. Check System Time
TLS validation is time‑sensitive. An out‑of‑sync clock makes valid certs appear expired.
date -u
# Sync with NTP
sudo timedatectl set-ntp true
3. Test with OpenSSL Using Specific Protocols
Sometimes the client and server cannot agree on a common protocol version.
# Force TLS 1.2
openssl s_client -tls1_2 -connect example.com:443 -servername example.com
# Force TLS 1.3
openssl s_client -tls1_3 -connect example.com:443 -servername example.com
If one version works and the other fails, adjust your server’s ssl_protocols directive accordingly.
4. Update the Trusted CA Store
Operating systems ship with a bundle of trusted CAs. An outdated bundle can reject newer certificates.
- Ubuntu/Debian:
sudo apt-get update && sudo apt-get install --only-upgrade ca-certificates
- RHEL/CentOS:
sudo yum update ca-certificates
- Alpine:
apk update && apk add ca-certificates && update-ca-certificates
5. Server Configuration Tips
Nginx Example
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/fullchain.crt; # leaf + intermediates
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3; # only modern protocols
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
}
Apache Example
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/example.com.crt
SSLCertificateKeyFile /etc/apache2/ssl/example.com.key
SSLCertificateChainFile /etc/apache2/ssl/intermediate.crt
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite HIGH:!aNULL:!MD5
6. Client‑Side Adjustments
-
Java: ensure the
cacertskeystore is up‑to‑date or import the missing intermediate usingkeytool. -
Python (requests): pass
verify=/path/to/ca-bundle.pemor updatecertifi. -
Curl: use
--tlsv1.2or--cacertto point at the right bundle.
Ready‑made Fix
If you prefer an automated solution, you can Download the pre‑configured script here or Get the complete patch tool. For a full repository, Access the full repository fix.
Conclusion
SSL/TLS handshake failures are rarely mystical—they’re usually the result of an expired/invalid certificate, a broken chain, time drift, or mismatched protocol settings. By following the systematic checks above, you can pinpoint the issue in minutes and restore secure communication for your users.
Top comments (0)