SSL handshake failed in nginx (ERR\_SSL\_PROTOCOL\_ERROR) - Rocketeers app

  [ Rocketeers ](/)   

[Login](https://rocketeersapp.com/login) 

 On this page

 Knowledge
---------

SSL handshake failed in nginx (ERR\_SSL\_PROTOCOL\_ERROR)
=========================================================

### [\#Errors](https://rocketeersapp.com/knowledge/errors)

A failed TLS handshake means the browser and nginx could not agree on a secure connection. The top causes are an expired certificate and a missing intermediate chain.

 Published by [Mark van Eijk](https://rocketeersapp.com/author/mark-van-eijk) on June 23, 2026 · 1 minute read

1. [About the error](#content-about-the-error)
2. [Why do I see this error](#content-why-do-i-see-this-error)
3. [Diagnose](#content-diagnose)
4. [Solution](#content-solution)
5. [Renew an expired certificate](#content-renew-an-expired-certificate)
6. [Serve the full chain](#content-serve-the-full-chain)
7. [Enforce modern protocols](#content-enforce-modern-protocols)

[\#](#content-about-the-error "Permalink")About the error
---------------------------------------------------------

The visitor sees `ERR_SSL_PROTOCOL_ERROR` or "SSL handshake failed", and nginx logs an SSL error. The handshake is the negotiation that happens before any data is exchanged, if it fails, the page never loads over HTTPS.

[\#](#content-why-do-i-see-this-error "Permalink")Why do I see this error
-------------------------------------------------------------------------

In production, almost always one of these:

- **Expired certificate**, the single most common cause.
- **Missing intermediate certificate**, nginx doesn't auto-fetch the chain, you must bundle it.
- **Wrong certificate or key path** in the config, or a key that doesn't match the certificate.
- **Outdated protocol**, the client requires TLS 1.2+ and the server only offers older versions.

[\#](#content-diagnose "Permalink")Diagnose
-------------------------------------------

Test the live handshake with OpenSSL. The `-servername` flag sends SNI, which is required when one IP serves multiple certificates:

 ```
openssl s_client -connect example.com:443 -servername example.com

```

Check the certificate's expiry date directly:

 ```
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

```

And read the nginx error log:

 ```
tail -f /var/log/nginx/error.log

```

[\#](#content-solution "Permalink")Solution
-------------------------------------------

### [\#](#content-renew-an-expired-certificate "Permalink")Renew an expired certificate

With Certbot:

 ```
sudo certbot renew
sudo systemctl reload nginx

```

Automate renewal so it never expires again, Certbot installs a timer for this by default.

### [\#](#content-serve-the-full-chain "Permalink")Serve the full chain

The `ssl_certificate` directive must point at the **full chain** (your certificate followed by the intermediates), not just the leaf certificate:

 ```
ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

```

A leaf-only certificate works in some browsers and fails in others, a classic intermittent handshake failure.

### [\#](#content-enforce-modern-protocols "Permalink")Enforce modern protocols

 ```
ssl_protocols TLSv1.2 TLSv1.3;

```

Validate and reload after any change:

 ```
nginx -t && systemctl reload nginx

```

For a hardened SSL setup behind a CDN, see [an A+ grade SSL using Cloudflare](/a-plus-grade-ssl-using-cloudflare). If the chain problem shows up in command-line tools rather than browsers, see [curl (60) SSL certificate problem](/curl-60-ssl-certificate-problem-unable-to-get-local-issuer-certificate). When these same problems reach a visitor's browser, they see [your connection is not private](/your-connection-is-not-private) or [NET::ERR\_CERT\_AUTHORITY\_INVALID](/net-err-cert-authority-invalid).

### Subscribe to our newsletter

Do you want to receive regular updates with fresh and exclusive content to learn more about web development, hosting, security and performance? Subscribe now!

  Fill in your email address to receive updates  Subscribe 

#### More in [\#Errors](https://rocketeersapp.com/knowledge/errors)

- [Error in the HTTP2 framing layer](https://rocketeersapp.com/knowledge/error-in-the-http2-framing-layer)
- [413 Request Entity Too Large in nginx](https://rocketeersapp.com/knowledge/413-request-entity-too-large)
- [403 Forbidden in nginx](https://rocketeersapp.com/knowledge/403-forbidden-nginx)
- [ERR\_TOO\_MANY\_REDIRECTS (redirect loop)](https://rocketeersapp.com/knowledge/err-too-many-redirects)
- [CORS error: No Access-Control-Allow-Origin header](https://rocketeersapp.com/knowledge/cors-error-no-access-control-allow-origin)
- [curl (60) SSL certificate problem: unable to get local issuer certificate](https://rocketeersapp.com/knowledge/curl-60-ssl-certificate-problem-unable-to-get-local-issuer-certificate)

 [View all 11 articles →](https://rocketeersapp.com/knowledge/errors)
