526 Invalid SSL Certificate
Server error response defined by developers.cloudflare.com.
Last updated July 27, 2026
Common causes at a glance
- The origin certificate expired and nothing renewed it
- A self-signed certificate on a zone set to Full (strict)
- An incomplete chain: the leaf is served without its intermediate CA
- The hostname is absent from the certificate's Common Name and SAN list
Reproduce it
openssl s_client -connect 203.0.113.10:443 -servername www.example.com -verify_return_error </dev/nullWhat 526 Invalid SSL Certificate means
The line between 526 and 525 is worth being precise about, because the fixes are unrelated. A 525 means no encrypted channel was established. A 526 means one was, and Cloudflare then rejected the certificate. The documented criteria are ordinary: not expired, not revoked, signed by a recognised CA rather than self-signed, hostname present in the Common Name or Subject Alternative Name, and a complete chain.
The mode requirement is narrower than for 525. Only Full (strict) validates origin certificates; plain Full encrypts without checking. That is why an expired origin certificate sits unnoticed for months and then takes the site down the moment somebody tightens the SSL/TLS mode.
There is no RFC
526 has no specification and no IANA registration. Cloudflare’s error documentation is the only definition. RFC 9110 §15 says an unrecognised 5xx must be handled as 500, so any monitor that does not special-case Cloudflare reports a generic server error. As with 525, the response comes from the edge. Your origin completed a handshake and then saw the connection close before a request arrived, which most web servers log as a truncated connection, if at all. Do not read a quiet access log as proof the origin is healthy.
What actually causes it
Expiry and incomplete chains account for most of these, and the incomplete chain is the crueller one because it is invisible in a browser. Browsers cache intermediates they have seen elsewhere and happily show a padlock for a server that only sends its leaf; Cloudflare’s edge rejects a chain it cannot build. The site looks fine to whoever tested it and returns 526 in production. Self-signed certificates are the deliberate version of the same problem — reasonable for origin traffic, but Full (strict) rejects them unless you load them into the Custom Origin Trust Store.
How to debug it
Validate against a real trust store rather than skipping verification, since skipping it is what hides the bug:
openssl s_client -connect 203.0.113.10:443 -servername www.example.com \
-verify_return_error </dev/null 2>&1 | grep -E 'Verify return|depth|subject='
A Verify return code: 0 (ok) means Cloudflare should accept it too.
Anything else names the problem: certificate has expired,
self signed certificate, or unable to get local issuer
certificate, which is the incomplete-chain message. Count the
depth lines too — depth 0 only is a leaf with no intermediate.
The TLS inspector shows expiry, SAN entries, and the served chain in one view. A Cloudflare Origin CA certificate is free and trusted by the edge by default. Downgrading to Full silences the error without fixing it.
Working examples
curl
# Validate properly — do not pass -k, it hides the exact failure.
openssl s_client -connect 203.0.113.10:443 \
-servername www.example.com -verify_return_error </dev/null 2>&1 \
| grep -E 'Verify return|depth|subject=|issuer='
# Expiry dates and SAN entries in one shot.
openssl s_client -connect 203.0.113.10:443 -servername www.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -dates -subject -ext subjectAltName
Python (requests)
import socket, ssl
# Full validation, exactly as Cloudflare's Full (strict) mode would do it.
ctx = ssl.create_default_context()
try:
with socket.create_connection(("203.0.113.10", 443), timeout=10) as sock:
with ctx.wrap_socket(sock, server_hostname="www.example.com") as tls:
cert = tls.getpeercert()
print("valid until:", cert["notAfter"])
print("SAN:", [v for k, v in cert.get("subjectAltName", ())])
except ssl.SSLCertVerificationError as exc:
# e.g. "certificate has expired", "unable to get local issuer certificate"
print("validation failed ->", exc.verify_message)
Node (fetch)
import tls from "node:tls";
// Default rejectUnauthorized mirrors Full (strict). If this errors,
// Cloudflare will return 526 for the same reason.
const sock = tls.connect(
{ host: "203.0.113.10", port: 443, servername: "www.example.com" },
() => {
const cert = sock.getPeerCertificate(true);
console.log("valid to:", cert.valid_to, "| SAN:", cert.subjectaltname);
console.log("chain:", cert.issuerCertificate ? "has intermediate" : "leaf only");
sock.end();
},
);
sock.on("error", (e) => console.log("rejected:", e.code)); // CERT_HAS_EXPIRED, etc.Reference and tooling
The authoritative list of assigned status codes is theIANA HTTP Status Code Registry. For a searchable copy with the semantics summarised, use theHTTP status code reference on this site. To see exactly what a server is sending, theheader inspector shows the raw status line and response headers, and thecurl builder assembles the request flags for you.
Other 5xx codes
- 500 Internal Server Error
- 501 Not Implemented
- 502 Bad Gateway
- 503 Service Unavailable
- 504 Gateway Timeout
- 505 HTTP Version Not Supported
- 506 Variant Also Negotiates
- 507 Insufficient Storage
- 508 Loop Detected
- 510 Not Extended
- 511 Network Authentication Required
- 520 Web Server Returns an Unknown Error
- 521 Web Server Is Down
- 522 Connection Timed Out
- 523 Origin Is Unreachable
- 524 A Timeout Occurred
- 525 SSL Handshake Failed
- 530 Unable to Resolve Origin Hostname