Skip to content

SecurityPart of: SSL and HTTPS

ERR_SSL_PROTOCOL_ERROR: what it means and how to fix it

ERR_SSL_PROTOCOL_ERROR means the browser and the server could not agree on a secure connection, so the handshake stopped before any page loaded. Here is the quick fix for visitors and the server-side causes for site owners.

getReport teamUpdated 26 Sept 202612 min read

ERR_SSL_PROTOCOL_ERROR is Chrome's message when the browser tried to open a secure HTTPS connection and the server answered with something that is not a valid TLS handshake, so the connection stopped before any page loaded. The page above it reads "This site can't provide a secure connection" and usually "example.com sent an invalid response". Most of the time the cause is on the server: port 443 is not set up for HTTPS. Sometimes it is on the visitor's device. This guide gives the two-minute visitor fix first, then the server-side causes and fixes. For how certificates and the TLS handshake work in general, start with what an SSL certificate is and how HTTPS works.

Quick answer

  • Visitor: try the site in a private window and on mobile data. If it works there, check your device's date and time, turn off HTTPS scanning in your antivirus or VPN, and clear the browser's cache. If it fails everywhere, the site is broken and only its owner can fix it.
  • Site owner: the usual cause is a server that speaks plain HTTP on port 443, or has no certificate for this host name. Test with openssl s_client -connect example.com:443 -servername example.com.
  • In nginx, listen 443; without ssl is the classic mistake: it must be listen 443 ssl; with a certificate.
  • Behind a CDN or load balancer, make sure the host name is actually added there and has an edge certificate.
  • After the fix, run the SSL checker to confirm the handshake, the certificate and the redirect.

What ERR_SSL_PROTOCOL_ERROR means

Every https:// page starts with a TLS handshake: the browser says hello, the server answers with its certificate, and both agree on keys. ERR_SSL_PROTOCOL_ERROR (Chrome's network error -107) means that exchange broke at the protocol level. The browser did not reject a certificate; it never got a usable one. The server sent bytes that are not TLS, closed the connection halfway, or sent a TLS alert the browser could not recover from.

That distinction tells you where to look:

What the browser showsWhat went wrong
ERR_SSL_PROTOCOL_ERROR, "sent an invalid response"The handshake itself failed: no TLS on the port, a broken configuration, something in the middle rewriting traffic
ERR_SSL_VERSION_OR_CIPHER_MISMATCH, "uses an unsupported protocol"TLS works, but the server only offers versions or ciphers the browser has dropped, such as TLS 1.0
"Your connection is not private" with a NET::ERR_CERT_… codeThe handshake worked, but the certificate is expired, for another name, or untrusted. See fixing "Your connection is not private"
Cloudflare 525 or 526 pageYour visitor reached Cloudflare fine; Cloudflare could not connect securely to your server. See Cloudflare errors 525 and 526

Other browsers name the same failure differently. Firefox shows "Secure Connection Failed" with a code such as SSL_ERROR_RX_RECORD_TOO_LONG, which almost always means plain HTTP on port 443. Safari says it "can't establish a secure connection to the server". Edge uses Chrome's wording.

If you're a visitor: the quick fix

If the error appears on one site only, the site is the likely cause, but a few things on your side produce the same message. Try these in order and stop when the page loads.

  1. Open the site in a private window, and on your phone over mobile data. If it works there, the problem is your browser or your network. If it fails everywhere, the site is broken; tell the owner and wait.
  2. Check your device's date and time. Set them to automatic. A clock that is days off breaks certificate checks and can break the handshake.
  3. Turn off HTTPS scanning in antivirus software and pause VPNs or proxy extensions. Security suites that inspect encrypted traffic sit in the middle of the handshake, and an outdated one can break it. If the site then works, update the software or add an exception.
  4. Clear cached data for the site. In Chrome: Settings → Privacy and security → Delete browsing data, "Cached images and files". On Windows, the old "Clear SSL state" button in Internet Options also clears cached certificates.
  5. Try another network. Company, school and hotel networks sometimes intercept HTTPS; a captive login page can too until you have signed in.

Avoid advice to turn on old TLS versions or disable security features in the browser's flags. Chrome removed those switches, and weakening your browser to reach one site is a bad trade.

Note

If you run the site yourself and see this on localhost or a .dev or .app domain, the browser is probably forcing HTTPS on a server that only speaks HTTP. .dev and .app are on the HSTS preload list, so browsers always use HTTPS for them; serve those domains over HTTPS, or use http://localhost instead.

If you own the site: find the cause

Start with a test from outside your network, so a local cache or VPN does not hide the problem.

The SSL checker connects like a strict client. When the HTTPS handshake fails, a report cannot load the page over https:// at all. If you typed the address without https://, getReport then tries http:// once: if that works, the report shows the site as served over HTTP, and if http:// redirects back to the broken https:// address, the report stops with "We could not reach that site". Either result points at the HTTPS setup, and these findings come back green once it works:

For the exact failure, use OpenSSL (on macOS and Linux it is built in; on Windows, Git Bash includes it):

Shell
openssl s_client -connect example.com:443 -servername example.com </dev/null

Read the output like this:

  • wrong version number or packet length too long: the server answered in plain HTTP. Port 443 is not configured for TLS.
  • Connection refused or a timeout: nothing listens on 443, or a firewall blocks it. Browsers usually show ERR_CONNECTION_REFUSED or ERR_CONNECTION_TIMED_OUT for this, not the protocol error.
  • alert unrecognized name or handshake failure before any certificate appears: the server has no certificate for this host name, or refuses the name you sent in SNI.
  • A certificate chain and Verify return code: 0 (ok): the handshake works from here. The problem is between the visitor and your server: a CDN, a firewall that inspects traffic, or the visitor's device.

Also try curl -vI https://example.com, which prints the same handshake steps with plain-language errors.

Server-side causes and fixes

Port 443 speaks plain HTTP

The most common cause. The web server listens on 443 but without TLS, so it answers the browser's hello with an HTTP response.

In nginx, ssl is missing from the listen line:

nginx
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    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;
}

In Apache, the <VirtualHost *:443> block needs SSLEngine on and the certificate lines, and mod_ssl must be enabled (sudo a2enmod ssl on Debian and Ubuntu). A common slip is a *:443 virtual host copied from the port 80 one without those lines.

In Node.js, Docker or an app server, the app often listens on 443 with plain HTTP because TLS was meant to happen in a reverse proxy in front of it. Put the proxy back in front, or terminate TLS in the app.

Reload after every change and test the configuration first: sudo nginx -t && sudo systemctl reload nginx, or sudo apachectl configtest && sudo systemctl reload apache2.

No certificate for this host name

A server with many sites picks the certificate by the name the browser sends (SNI). If www.example.com or a new subdomain has no matching server block or virtual host, the request falls through to a default one. Depending on how that default is set up, the browser gets another site's certificate ("Your connection is not private") or no certificate at all (the protocol error). nginx's ssl_reject_handshake on; in a default block, for example, deliberately refuses unknown names.

Fix it by adding the name to the site's configuration and issuing a certificate that covers it. With Let's Encrypt this is one command, covered in getting a free certificate with Let's Encrypt.

A broken certificate or key file

If the certificate and private key do not match, or a file is empty or truncated after a failed renewal, nginx or Apache usually refuses to start. Some servers and panels start anyway and fail every handshake. Check that the two belong together; the outputs must be identical:

Shell
openssl x509 -noout -pubkey -in fullchain.pem | openssl sha256
openssl pkey -pubout -in privkey.pem | openssl sha256

Only old protocols on the server

A server that only accepts TLS 1.0 or 1.1 shows ERR_SSL_VERSION_OR_CIPHER_MISMATCH in current browsers rather than the protocol error, but the fix is in the same place: allow TLS 1.2 and 1.3. The finding below flags a server that still accepts the old versions:

A CDN, load balancer or firewall in the middle

With a CDN or cloud load balancer in front, the visitor's handshake happens there. If the host name is not added to the CDN, or its edge certificate is still being issued (usually minutes after adding a domain), visitors can get a protocol error while your server is fine. Check the CDN's dashboard for the certificate status of the exact name. Behind Cloudflare, the errors between Cloudflare and your server show as 525 or 526 instead.

A web application firewall or intrusion prevention box that inspects TLS can also break handshakes, especially with TLS 1.3. Test from a network that bypasses it.

HSTS on a site that dropped HTTPS

If your site once sent Strict-Transport-Security, browsers that saw it will only use HTTPS for your domain until max-age runs out, often a year. Moving to a host without HTTPS then breaks those visitors with a protocol or certificate error, and there is no way to undo it from the server. The only fix is to serve HTTPS again. HSTS: enabling it safely covers why you set it only once HTTPS is stable everywhere.

How to verify the fix

  1. openssl s_client -connect example.com:443 -servername example.com shows your certificate and Verify return code: 0 (ok).
  2. Repeat for every name visitors use: example.com, www.example.com and any subdomain.
  3. Open the site in a private window on desktop and on a phone over mobile data.
  4. Run the SSL checker: the HTTPS, redirect, chain and TLS version findings should pass, with 30 or more days left on the certificate.
  5. Check the redirect: http://example.com should reach https://example.com in one 301.

Common mistakes

  • listen 443; without ssl in nginx. Everything looks configured, and every visitor gets the protocol error.
  • Adding a new subdomain to DNS but not to the web server or certificate. The name reaches the server and falls through to the wrong site.
  • Pointing a domain at a new host before its certificate is issued. Issue the certificate first, or accept a few minutes of errors after the DNS switch.
  • Telling visitors to clear their cache when the server is broken. If the openssl test fails from outside, no visitor-side fix will help.
  • Turning HSTS on with a long max-age before HTTPS works on every subdomain.

Questions people ask

How do I fix ERR_SSL_PROTOCOL_ERROR?

First find out whose side it is on. If the site fails in a private window, on another device and on mobile data, the server is the cause: its port 443 is not serving TLS for that host name, so the owner has to fix the web server or CDN configuration. If it works elsewhere, fix your device: set the clock to automatic, turn off HTTPS scanning in antivirus software or VPNs, and clear the browser's cached files.

What does "This site can't provide a secure connection" mean?

It means Chrome tried to open the page over HTTPS and the secure handshake with the server failed, so it showed nothing rather than an unprotected page. The line under it, usually "sent an invalid response" with ERR_SSL_PROTOCOL_ERROR, says the server did not answer in TLS. It is not a warning you can click through: the site has to serve HTTPS properly, or your device must stop interfering with the connection.

Can a website owner cause ERR_SSL_PROTOCOL_ERROR?

Yes, and usually they do. The most common causes are a server that answers plain HTTP on port 443, a host name with no certificate configured, a mismatched certificate and key after a renewal, or a CDN that has not issued its certificate for the domain yet. An openssl s_client test from outside shows which one, and the SSL checker confirms the fix.

Why does ERR_SSL_PROTOCOL_ERROR appear on localhost?

Because the browser asked for https://localhost and your development server only speaks plain HTTP. That happens when you type https://, when an app redirects to HTTPS, or when an earlier HTTPS project on localhost set HSTS. Open http://localhost:port instead, remove the redirect in development, or delete the domain's security policy at chrome://net-internals/#hsts if HSTS was cached.

Is ERR_SSL_PROTOCOL_ERROR dangerous?

No, not in itself: it means the browser refused to load a page because it could not set up encryption, which protects you. It does not mean you were attacked. On a network you do not trust, such as public Wi-Fi, do not try to work around it with another browser or an old protocol; wait until you are on a known network or the site owner has fixed it.

Check your site before and after Check