Short answer: error 525, “SSL handshake failed,” means Cloudflare reached your server but could not complete a TLS handshake with it — the server did not answer on port 443 the way Cloudflare expected. It is a connection problem between Cloudflare and your origin, not between the visitor and Cloudflare, so nothing about the visitor’s browser or connection is the cause.
What actually causes a 525
| Cause | Why it breaks the handshake |
|---|---|
| Nothing listening on port 443 | No TLS to negotiate at all — check the web server is running and bound to 443 |
| SSL mode set to Full or Full (strict), no certificate on the origin | Cloudflare insists on HTTPS to the origin in these modes; a plain HTTP-only origin has nothing to negotiate |
| Expired or missing origin certificate | The handshake starts, then fails when the certificate itself is invalid or absent |
| Cipher suite mismatch | An old web server offering only ciphers Cloudflare's edge refuses, or the reverse |
| Missing SNI support on the origin | The origin can't match the requested hostname to a certificate when several sites share one IP |
| A firewall or security group blocking Cloudflare's IP ranges on 443 | The handshake never starts because the TCP connection itself is dropped |
Step 1: check your Cloudflare SSL/TLS mode
In the dashboard, SSL/TLS → Overview, see which mode is set:
| Mode | Connects to origin over | Origin needs |
|---|---|---|
| Off | HTTP only | Nothing — and the site is unencrypted to visitors too, not recommended |
| Flexible | HTTP | Nothing on 443; works even with no origin certificate |
| Full | HTTPS | Any certificate on 443, self-signed included |
| Full (strict) | HTTPS | A valid certificate on 443, trusted by a public CA or Cloudflare's own Origin CA |
A 525 under Full or Full (strict) means the origin needs to answer HTTPS on 443 and currently does not, or does so with a certificate or cipher set Cloudflare’s edge rejects. Switching to Flexible makes the error disappear by no longer asking the origin for HTTPS at all — that hides the symptom rather than fixing it, and leaves the Cloudflare-to-origin leg of the connection unencrypted, so treat it as a temporary check, not the fix.
Step 2: confirm the origin is actually listening on 443
sudo ss -tlnp | grep ':443'Nothing in the output means no process has the port open at all — start or fix nginx, Apache or whatever terminates TLS before going further. If something does show up, test the handshake directly, bypassing Cloudflare, by connecting straight to the server’s own IP address:
openssl s_client -connect 203.0.113.10:443 -servername example.comA working handshake ends with a certificate chain and Verify return code: 0 (ok) or a specific, readable error if it is not trusted — either way, the connection completes. If this hangs or is refused, the problem is entirely on the origin or its firewall, before Cloudflare even enters the picture.
Step 3: allow Cloudflare’s IP ranges through the firewall
If a firewall or cloud security group only allows specific addresses in on 443, it has to include Cloudflare’s published IP ranges, or every request — not just some — fails the same way:
curl -s https://www.cloudflare.com/ips-v4 | while read -r ip; do
sudo ufw allow from "$ip" to any port 443 proto tcp
doneFor a handshake that fails without Cloudflare in the picture at all — a browser talking straight to your server — see SSL handshake failed, which covers cipher and protocol mismatches in more depth.
Step 4: check the origin certificate itself
openssl x509 -in /etc/ssl/certs/example.com.pem -noout -dates -subjectAn expired certificate, or one that does not list the hostname Cloudflare is requesting, fails the handshake under Full (strict) specifically — Full accepts a self-signed or otherwise untrusted certificate, but both modes still require the hostname to match if SNI is in play.
525 vs the other Cloudflare 52x errors
| Error | Meaning |
|---|---|
| 520 | Origin returned an empty or invalid HTTP response |
| 521 | Origin refused the connection outright |
| 522 | Connection to the origin timed out |
| 523 | Origin is unreachable — DNS or routing problem |
| 524 | Origin accepted the connection but took too long to respond (timeout) |
| 525 | SSL handshake between Cloudflare and the origin failed |
| 526 | Origin's SSL certificate is invalid (expired, wrong hostname, untrusted) |
525 and 526 are easy to mix up: 525 is the handshake itself failing to complete — no cipher agreement, no SNI match, nothing listening — while 526 is a handshake that completes but hands over a certificate Cloudflare does not accept under Full (strict).
If the connection succeeds but nothing comes back in time, that is error 524, a timeout, not a TLS problem at all.
An origin that connects fine over plain HTTP but breaks under HTTPS specifically often shows as 525 under Full/Full (strict) and as error 520 under Flexible — same underlying server issue, different symptom depending on the SSL mode.
Frequently asked
What does Cloudflare error 525 mean?
Cloudflare reached your server but could not complete a TLS handshake with it on port 443 — a certificate problem, a cipher mismatch, or nothing listening there at all. It is strictly between Cloudflare and your origin; the visitor's connection to Cloudflare is unaffected.
Does switching to Flexible SSL fix error 525?
It makes the error disappear because Cloudflare stops requesting HTTPS from the origin at all — but that leaves the Cloudflare-to-origin leg of the connection unencrypted. Treat it as a diagnostic step, not the actual fix.
How do I test the SSL handshake directly, without Cloudflare in the way?
openssl s_client -connect YOUR_SERVER_IP:443 -servername yourdomain.com from your own computer, connecting straight to the origin's IP. A completed handshake with a certificate chain means the origin is fine and the problem is specific to Cloudflare's connection to it.
What is the difference between error 525 and error 526?
525 is the handshake itself failing to complete at all. 526 is a handshake that completes but hands over a certificate Cloudflare's Full (strict) mode does not trust — expired, wrong hostname, or self-signed.