# Fix Nginx SSL Handshake Failed with TLS 1.2 Client Browsers
When clients report SSL handshake failures to your Nginx server, the error log shows entries like this:
2026/04/08 11:42:33 [info] 2341#2341: *34567 SSL_do_handshake() failed (SSL: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:SSL alert number 40) while SSL handshaking, client: 192.0.2.50, server: 0.0.0.0:443This specific alert -- sslv3 alert handshake failure -- means the client and server could not agree on a common TLS protocol version or cipher suite. The client sends its list of supported ciphers, the server responds with its own, and if there is no overlap, the handshake fails.
Diagnosing the Mismatch
Use OpenSSL to test which protocols and ciphers your Nginx accepts:
echo | openssl s_client -connect example.com:443 -tls1_2 2>&1 | grep -E "Protocol|Cipher"If the command fails with handshake failure, Nginx is not configured to accept the client's cipher preferences. Test all protocol versions:
echo | openssl s_client -connect example.com:443 -tls1 2>&1 | grep "Protocol"
echo | openssl s_client -connect example.com:443 -tls1_1 2>&1 | grep "Protocol"
echo | openssl s_client -connect example.com:443 -tls1_2 2>&1 | grep "Protocol"
echo | openssl s_client -connect example.com:443 -tls1_3 2>&1 | grep "Protocol"Common Cause 1: TLS 1.2 Disabled
Check your Nginx SSL configuration:
grep ssl_protocols /etc/nginx/nginx.confIf you see only TLSv1.3, TLS 1.2 clients cannot connect. Fix it:
ssl_protocols TLSv1.2 TLSv1.3;Many organizations still have clients that only support TLS 1.2: older Android devices (pre-5.0), Windows 7 without updates, legacy enterprise systems, and some IoT devices.
Common Cause 2: Cipher Suite Mismatch
The ssl_ciphers directive may be too restrictive. A balanced configuration that supports TLS 1.2 clients while maintaining security:
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;Setting ssl_prefer_server_ciphers off allows the client to choose its preferred cipher from the intersection of both lists, which reduces handshake failures.
Common Cause 3: Missing Intermediate Certificate
If the server certificate chain is incomplete, clients cannot validate the handshake. Test:
echo | openssl s_client -connect example.com:443 -showcerts 2>&1 | grep "Certificate chain" -A 20You should see the full chain: leaf certificate, intermediate(s), and root. If the intermediate is missing, combine the certificates:
cat /etc/letsencrypt/live/example.com/cert.pem /etc/letsencrypt/live/example.com/chain.pem > /etc/letsencrypt/live/example.com/fullchain.pemThen update Nginx:
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;ECDSA vs RSA Certificate Issue
If you are using an ECDSA certificate but some clients only support RSA key exchange, you may need to serve both:
```nginx server { listen 443 ssl; server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.rsa.pem; ssl_certificate_key /etc/ssl/private/example.com.rsa.key;
ssl_certificate /etc/ssl/certs/example.com.ecdsa.pem; ssl_certificate_key /etc/ssl/private/example.com.ecdsa.key;
ssl_protocols TLSv1.2 TLSv1.3; } ```
Nginx will negotiate the appropriate certificate based on the client's capabilities.
Testing the Fix
After reloading Nginx:
sudo nginx -t && sudo systemctl reload nginxRun the full test suite:
echo | openssl s_client -connect example.com:443 -tls1_2 2>&1 | grep "Verify return code"
nmap --script ssl-enum-ciphers -p 443 example.com
./testssl.sh https://example.comThe testssl.sh tool will show you exactly which clients (browsers, operating systems) can and cannot connect to your server, along with the grade for your SSL configuration.