
What it means: Chrome started a TLS handshake, but the server's reply was not valid TLS, so the connection was dropped.
Free online tool — SSL certificate checker: instant results, no signup.
Runs a full TLS check: handshake, protocol versions, certificate chain, trust and expiry.
ERR_SSL_PROTOCOL_ERROR is Chromium net error -107, described in the source as “An SSL protocol error occurred.” It is a catch-all: when BoringSSL, Chrome's TLS library, aborts a handshake for a reason that has no dedicated Chrome code, Chrome's error mapping falls back to ERR_SSL_PROTOCOL_ERROR. The error page reads “This site can't provide a secure connection” followed by “host sent an invalid response.”
The failure sits at the TLS layer. DNS resolved and the TCP connection opened, but the bytes that came back were not a TLS handshake Chrome could accept. It is not a certificate problem (those are ERR_CERT_* codes on a “Your connection is not private” page), not a wrong system clock (that gives ERR_CERT_DATE_INVALID), and usually not a version or cipher disagreement: Chrome maps “no common TLS version or cipher” to ERR_SSL_VERSION_OR_CIPHER_MISMATCH. A server that only speaks TLS 1.0 or 1.1 therefore produces the mismatch error, not this one.
| Browser | What you see | Most common trigger |
|---|---|---|
| Chrome, Edge, Brave, Opera | ERR_SSL_PROTOCOL_ERROR, “sent an invalid response” | Plain HTTP answering on an https:// URL or port |
| Firefox | SSL_ERROR_RX_RECORD_TOO_LONG for the plain-HTTP case; other handshake faults get their own NSS codes | Same server-side fault, reported by NSS |
| Safari | “Safari can't establish a secure connection to the server”, no code | Same server-side fault |
The triggers that actually produce this code, roughly from most to least common:
listen 443; without ssl, a Docker mapping like 443:80, a load balancer forwarding 443 to an HTTP backend, or https:// typed for a dev server that only speaks HTTP. The server answers the ClientHello with an HTTP 400 page, which cannot be parsed as a TLS record..dev or .app, has HSTS, http://host:8080 is rewritten to https://host:8080; if that port speaks HTTP, you get this error.Two things that look related but are not: HTTP/3 failures run over QUIC and carry their own codes such as ERR_QUIC_PROTOCOL_ERROR, so disabling QUIC does not fix this error. And middleboxes that choke on the larger post-quantum ClientHello Chrome has sent since version 124 typically cause dropped or reset connections (ERR_CONNECTION_RESET), not this code.
The browser's TLS session ends at the first TLS terminator, so this error is about that hop. Origin TLS failures behind Cloudflare appear as Cloudflare 525 or 526 pages, not as ERR_SSL_PROTOCOL_ERROR.
server {
listen 443 ssl; # without "ssl" this port answers in plain HTTP
listen [::]:443 ssl; # the IPv6 line needs "ssl" too
http2 on; # nginx 1.25.1+; older: listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
}A classic partial outage: listen 443 ssl; is correct but listen [::]:443; lacks ssl. Visitors who reach the site over IPv4 are fine; everyone with working IPv6 gets ERR_SSL_PROTOCOL_ERROR.
With the DNS record proxied (orange cloud), Cloudflare terminates TLS at its edge, so a misconfigured origin port cannot produce this code in the browser. It can appear when the record is DNS only (grey cloud) or Cloudflare is paused: browsers then connect straight to your origin, which must serve real TLS on 443 itself.
A TCP-mode frontend on 443 that forwards to an HTTP backend produces the plain-HTTP symptom exactly. Either terminate TLS on the frontend (bind :443 ssl crt /etc/haproxy/certs/example.pem) or make sure the backend itself speaks TLS.
curl -sv https://example.com/ -o /dev/null
# "wrong version number" in the TLS error = the port answered in plain HTTP
curl -si http://example.com:443/ | head -1
# an HTTP status line here confirms itopenssl s_client -connect example.com:443 -servername example.com -brief </dev/null. A healthy server prints the protocol version and cipher; garbage or an immediate error points at the listener. Repeat against the IPv6 address with -connect '[2001:db8::10]:443'.ssl to every listen on 443, then nginx -t && systemctl reload nginx. In Docker, docker ps must not show 0.0.0.0:443->80/tcp unless the container terminates TLS on 80.chrome://net-export, reproduce the error, stop logging and look for the SSL_HANDSHAKE_ERROR event: it records the underlying BoringSSL error reason that ERR_SSL_PROTOCOL_ERROR hides.chrome://net-internals/#sockets offers “Flush socket pools” for the same effect.localhost or your own test domain is being forced to https, delete its entry at chrome://net-internals/#hsts.Clearing the cache and cookies does not help: certificates and handshakes are not stored in the HTTP cache. A wrong system clock is not the cause either. If the error appears on every network, device and browser, the fault is on the server and only the site owner can fix it.
openssl s_client -connect example.com:443 -servername example.com -brief </dev/null
# CONNECTION ESTABLISHED
# Protocol version: TLSv1.3
curl -sI https://example.com/ | head -1
# HTTP/2 200Run both over IPv4 and IPv6 (curl -4, curl -6) if the site has an AAAA record. To check the handshake, protocol versions and certificate from outside your network, run the domain through the SSL/TLS checker.
SSL/TLS is the encryption protocol that protects data between the browser and server. Our tool analyzes the certificate, chain of trust, TLS version, and knownvulnerabilities.
Issuer, validity period, signature algorithm, covered domains (SAN), and validation type (DV/OV/EV).
Full chain verification: from leaf certificate through intermediates to root CA.
Protocol version (TLS 1.2/1.3), cipher suites, Perfect Forward Secrecy (PFS) support.
Set up a monitor — get Telegram and email alerts 30/14/7 days before expiration.
SSL certificate monitoring
TLS config audit
HTTPS as ranking factor
customer trust
www and subdomains.Strict-Transport-Security header forces browsers to always use HTTPS.SSL certificate monitoring, check history and alerts 30 days before expiry.
Sign up freeThere is nothing to bypass: no secure connection was established, so Chrome offers no Proceed link. Typing thisisunsafe, an undocumented Chrome bypass that may change, only works on certificate warning pages, not on this error.
HSTS covers every port of a host, and preloaded TLDs such as .dev and .app are HTTPS-only, so the browser sends TLS to a port that speaks plain HTTP. For your own dev host, delete its entry at chrome://net-internals/#hsts or serve TLS on that port.
Something on that path is intercepting TLS: a corporate proxy, antivirus HTTPS scanning, a VPN client or router filtering. It can also be IPv6: if the IPv6 listener lacks TLS, only devices with working IPv6 fail.
Each browser names the failure in its own words. For plain HTTP on port 443, Firefox reports SSL_ERROR_RX_RECORD_TOO_LONG and Safari says it cannot establish a secure connection; the server fix is the same.
Not normally. Date problems show up as ERR_CERT_DATE_INVALID on a privacy warning page. ERR_SSL_PROTOCOL_ERROR means the handshake itself broke before certificate checks mattered.
Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.