Cloudflare Error 525: SSL handshake failed
Cloudflare knocked on port 443 and the TCP path worked — then the TLS handshake fell apart. The origin is not speaking a TLS dialect Cloudflare can agree on, or nothing on 443 is speaking TLS at all.
What visitors see
Error 525
SSL handshake failed
The SSL handshake between Cloudflare and the origin web server failed.
Cloudflare Ray ID: …
This only appears when the zone’s SSL/TLS mode talks HTTPS to the origin (Full or Full strict). Flexible mode uses HTTP:80 to the origin and will not produce a 525 from a broken origin TLS stack.
525 vs 526 vs browser TLS errors
| Symptom | Layer | Typical cause |
|---|---|---|
| Cloudflare 525 | CF → origin TLS handshake failed | Origin not speaking TLS on 443, protocol/cipher/SNI mismatch |
| Cloudflare 526 | CF → origin handshake reached cert check | Expired, self-signed, wrong name, or untrusted origin cert under Full (strict) |
| ERR_SSL_PROTOCOL_ERROR | Browser → edge (or direct) | Client path; not the same as CF↔origin 525 |
| SSL wrong version number | Client expected TLS, got plain HTTP (or vice versa) | http:// to a TLS-only port, or TLS to an HTTP-only port |
| ERR_SSL_VERSION_OR_CIPHER_MISMATCH | Browser ↔ server cipher/version | Same idea as 525, different client |
| 521 / 522 | CF → origin TCP | Nothing listening / timeout — handshake never starts |
Rule of thumb: if openssl s_client -connect ORIGIN:443 fails before a certificate appears, think 525. If a certificate prints but verification fails under Full (strict), think 526.
Cloudflare SSL/TLS modes (why 525 appears)
- Flexible — Cloudflare ↔ visitor is HTTPS; Cloudflare ↔ origin is HTTP:80. Origin TLS does not matter. Misconfigured Flexible + an origin that redirects HTTP→HTTPS can cause redirect loops (too many redirects), not 525.
- Full — Cloudflare ↔ origin is HTTPS. Handshake must succeed; cert can be self-signed or otherwise untrusted. Handshake failure → 525.
- Full (strict) — like Full, but the origin certificate must also be valid and trusted (hostname match, not expired, chain to a trusted CA — Cloudflare Origin CA counts). Bad cert after a successful handshake path → 526; handshake never completing → still 525.
Frequent real causes
- Nothing speaking TLS on 443 — nginx/Caddy listening HTTP only; a plain Node
http.createServerbound to 443; or SSL mode Full while only :80 is open (TCP may still accept, then the first TLS ClientHello gets HTTP garbage → handshake fail / wrong-version family). - Wrong SSL mode for the origin — Full/Full strict against an HTTP-only origin. Either install TLS on the origin or (as a temporary stopgap) use Flexible — knowing Flexible leaves origin traffic in cleartext on the last hop.
- Cipher or protocol mismatch — origin locked to obsolete TLS 1.0 / rare ciphers Cloudflare no longer offers, or only TLS 1.3 while an intermediate breaks it. Same spirit as cipher mismatch.
- SNI issues — origin requires SNI and the certificate map has no entry for the Host Cloudflare presents; default vhost speaks plain HTTP or closes.
- Broken / partial TLS config — missing intermediate, wrong
ssl_certificatepath so the listener fails oddly, or a load balancer terminating TLS incorrectly before the origin.
Diagnose with openssl and curl
# From a machine that can reach the origin IP (bypass Cloudflare):
openssl s_client -connect ORIGIN_IP:443 -servername example.com -tls1_2 </dev/null
openssl s_client -connect ORIGIN_IP:443 -servername example.com -tls1_3 </dev/null
# Expect a certificate dump and "Verify return code: …" on success.
# "wrong version number", immediate close, or handshake failure → 525-class.
curl -vI https://ORIGIN_IP/ -H "Host: example.com" -k --connect-timeout 5
# On the origin:
sudo ss -ltnp | grep -E ':443|:80'
sudo nginx -t
# Confirm the :443 server block has ssl_certificate / ssl_certificate_key
# Cloudflare dashboard → SSL/TLS → Overview: Flexible vs Full vs Full (strict)
If openssl shows the peer speaking plain HTTP on 443, you have an SSL-mode vs listener mismatch — classic 525 fuel. For “certificate appeared but verify failed”, switch to the 526 guide.
Fix checklist
- Confirm SSL mode — Flexible → HTTP:80 to origin (no 525 from origin TLS). Full / Full strict → origin must speak TLS on 443.
- Prove TLS on the origin —
openssl s_client -servername …must complete a handshake. Install or repair the origin certificate (Cloudflare Origin CA or Let’s Encrypt). - Match protocols and ciphers — allow TLS 1.2+ with a modern cipher suite; drop ancient-only configs.
- Fix SNI / vhost map — every hostname Cloudflare proxies must have a matching certificate server name on the origin.
- Do not leave Full pointed at HTTP-only — that is a permanent 525. Either add TLS or temporarily switch mode while you install a cert.
- After handshake works — under Full (strict), a bad cert becomes 526; under Full, a self-signed cert is allowed. See also certificate has expired and self-signed certificate in certificate chain.
Related
All Cloudflare error codes · Cloudflare Error 523 · Cloudflare Error 526 · certificate has expired · self-signed certificate in certificate chain · unable to get local issuer certificate · ERR_SSL_PROTOCOL_ERROR · SSL wrong version number · ERR_SSL_VERSION_OR_CIPHER_MISMATCH · Cloudflare Error 521 · Cloudflare Error 522 · Cloudflare Error 520 · Anvil HTTP status · Wirebook: when sites get tired
Questions
What does Cloudflare Error 525 mean?
Cloudflare connected to your origin on 443 but the TLS handshake failed — often the origin is not speaking TLS, or protocols/ciphers/SNI do not match.
How is 525 different from 526?
525 fails during the handshake itself. 526 means the handshake path got far enough to validate the certificate and the cert was invalid under Full (strict).
Does Flexible mode cause 525?
No. Flexible uses HTTP to the origin, so origin TLS never runs. 525 appears under Full or Full (strict).
How do I fix Error 525?
Make the origin speak working TLS on 443 (openssl s_client should succeed), align Cloudflare SSL mode with that, and fix cipher/protocol/SNI mismatches.
Can a self-signed certificate cause 525?
Usually not under Full (self-signed is allowed there). A self-signed or otherwise untrusted cert under Full (strict) is typically Error 526. A completely broken TLS listener is 525.
Why does openssl say wrong version number?
You are speaking TLS to a port that answers in plain HTTP (or the reverse). Point Full mode at a real HTTPS listener, or use Flexible only as a temporary HTTP:80 path.
Is 525 the same as ERR_SSL_PROTOCOL_ERROR in Chrome?
Same family of idea (TLS failed), different path. Browser errors are client↔site; 525 is specifically Cloudflare↔origin.
Published .