sfw/fix
ERR_SSL_PROTOCOL_ERROR high

ERR_SSL_PROTOCOL_ERROR

Chrome connected to the server but the TLS handshake failed, usually from an outdated protocol, bad cipher match, or broken cert chain.

What you see

This site can't provide a secure connection
example.com sent an invalid response.
ERR_SSL_PROTOCOL_ERROR

What’s actually happening

Chrome reaches the server — the TCP connection opens — but bails during the TLS handshake and shows 'This site can't provide a secure connection'. Plain HTTP may load while HTTPS won't. Other clients sometimes behave differently: an older curl or a different browser might connect, which points at a protocol or cipher negotiation problem rather than the server being down. It often shows up right after a TLS config change, a cert renewal, or disabling old protocol versions.

Common causes

  • The server only offers protocol versions modern Chrome refuses — TLS 1.0/1.1 are disabled in current Chrome, so a server stuck on them has nothing to negotiate
  • No overlap in cipher suites — the server's list is all legacy (RC4, 3DES, export ciphers) and Chrome won't touch any of them
  • The cert chain is incomplete: the intermediate certificate is missing, so the handshake can't build a path even though the leaf cert is valid
  • A reverse proxy / load balancer terminating TLS is misconfigured, or two services fight over the same port (e.g. HTTP being served on 443)
  • SNI mismatch or wrong default vhost — the server presents a cert that doesn't match the requested host and the handshake aborts

How to fix it

  1. See exactly where the handshake breaksFrom a shell: openssl s_client -connect example.com:443 -servername example.com. Watch for the protocol and cipher actually negotiated, and whether the chain shows 'unable to get local issuer certificate'. Then run an external scan — SSL Labs (ssllabs.com/ssltest) or testssl.sh — which spells out enabled protocols, cipher list, and chain gaps in one report.
  2. Enable a modern protocol versionMake sure TLS 1.2 (and ideally 1.3) is on. Nginx: ssl_protocols TLSv1.2 TLSv1.3;. Apache: SSLProtocol -all +TLSv1.2 +TLSv1.3. If the server was pinned to TLS 1.0/1.1 for some legacy client, that's the exact thing Chrome now rejects — you can't keep both.
  3. Fix the cipher suite listSet a sane, current cipher string rather than whatever shipped years ago. Use Mozilla's SSL Config Generator for your server and version (intermediate profile is the usual choice). In Nginx: ssl_ciphers with the generated list plus ssl_prefer_server_ciphers off; for TLS 1.3. An all-legacy cipher list gives Chrome nothing in common to pick.
  4. Install the full certificate chainServe leaf + intermediate(s), not just the leaf. With Nginx the ssl_certificate file must be the fullchain (cert then intermediates concatenated), not cert.pem alone — Let's Encrypt's fullchain.pem already does this. A missing intermediate is invisible in some browsers (they cache it) but breaks others, which looks like an intermittent ERR_SSL_PROTOCOL_ERROR.
  5. Check what's really bound to 443Confirm the TLS-terminating process owns the port and nothing else is interfering: ss -tlnp | grep :443. If a plain-HTTP app or a second service is on 443, the bytes Chrome gets back aren't a valid TLS record and the handshake dies. Behind a proxy (Nginx → app, or an ELB), verify TLS is terminated at one place with a valid cert and the right SNI default.

Stop it recurring

Pin a modern protocol and cipher set from Mozilla's generator, deploy the full chain (fullchain.pem), and re-run an SSL Labs scan after every cert renewal or TLS config change.

Related errors