SSL / TLS Guide

SSL Certificate Errors Explained: What Every NET::ERR_CERT Error Means and How to Fix It

SSL certificate errors block 100% of HTTPS traffic to your site instantly — no 5xx, no fallback, just a browser warning page that most users cannot bypass. Understanding exactly which error is showing and why is the first step to fixing it in under 10 minutes.

Quick Error Reference

NET::ERR_CERT_DATE_INVALID → Certificate expired. Renew it.
NET::ERR_CERT_AUTHORITY_INVALID → Untrusted CA or incomplete chain. Install full chain.
NET::ERR_CERT_COMMON_NAME_INVALID → Hostname mismatch. Reissue cert with correct SAN.
SSL_ERROR_RX_RECORD_TOO_LONG → HTTP served on HTTPS port. Fix server config.
ERR_SSL_PROTOCOL_ERROR → TLS handshake failed. Check TLS version and cipher compatibility.

How TLS Certificate Validation Works (The Chain of Trust)

When your browser connects to an HTTPS site, it performs a multi-step certificate validation before allowing any data to be exchanged — if any step fails, it displays an error page and blocks the connection entirely. The validation checks four properties: that the certificate is currently within its validity period, that it was signed by a trusted Certificate Authority, that the hostname matches the certificate’s subject, and that the full certificate chain (from leaf to root) is present and unbroken. A failure at any of these four checks produces a specific error code identifying which check failed.

🏭

Root Certificate Authority

Self-signed certificates pre-installed in your OS and browser (Mozilla, Apple, Microsoft, Google root stores). Examples: ISRG Root X1 (Let’s Encrypt), DigiCert Global Root CA. These are the ultimate trust anchors — implicitly trusted by browsers without needing to verify them against anything else.

Trusted by OS/Browser
👥

Intermediate Certificate Authority

A CA certificate signed by the root CA. Intermediate CAs do the actual signing of website certificates. Example: “R3” (Let’s Encrypt’s intermediate CA). Your server must send this certificate alongside your leaf certificate — if it’s missing, browsers that haven’t cached it will show ERR_CERT_AUTHORITY_INVALID.

Must be served by server
📄

Leaf Certificate (Your Certificate)

The certificate issued to your domain (e.g., example.com). Contains your domain name in the Subject Alternative Names (SAN) field, the validity period (notBefore and notAfter dates), and the public key your server uses for TLS. This is what browsers display in the padlock details.

Your domain’s cert
🌐

Browser / Client

Validates the full chain: leaf cert → intermediate CA → root CA. Checks the notAfter date against current time. Checks that the SAN contains the hostname being visited. If all checks pass: green padlock. If any check fails: error page, connection blocked.

Validates the full chain

The most important operational implication of the chain of trust: your server must send the leaf certificate AND all intermediate CA certificates in the TLS handshake. Root CA certificates are pre-installed in browsers. Intermediate CA certificates are not — browsers must receive them from your server or retrieve them via AIA (Authority Information Access) extension. Many server misconfiguration incidents are caused by deploying only the leaf certificate without the intermediate chain, which works for some browsers (that cache or fetch intermediates) but fails for others.

Test your certificate chain: Use SSL Labs’ SSL Test (ssllabs.com/ssltest) to verify your server sends a complete certificate chain. An “A+” rating requires the full chain, correct hostname matching, valid dates, and strong cipher configuration. The test also checks for HSTS, CAA records, and OCSP stapling — all of which affect HTTPS reliability.

NET::ERR_CERT_DATE_INVALID — Expired Certificate

NET::ERR_CERT_DATE_INVALID
Chrome Edge
Firefox: SEC_ERROR_EXPIRED_CERTIFICATE Safari: This certificate has expired

Certificate has passed its notAfter expiry date

Root cause: Every TLS certificate has a notAfter field specifying the exact UTC timestamp at which it expires. Browsers check this field against the current time on every HTTPS connection. The moment the certificate’s notAfter timestamp passes, every browser in the world blocks access with this error simultaneously — there is no grace period, no warning to users, no fallback. The certificate is rejected regardless of how recently it was valid or how trusted the CA is.

Modern TLS certificates from public CAs have 90-day or 398-day maximum validity periods (Apple mandated the 398-day cap for certificates trusted on Apple devices from 2020). Let’s Encrypt issues 90-day certificates, which is why its certbot client auto-renews at 60 days remaining. Commercial certificates from DigiCert, Sectigo, and GlobalSign allow 1-year (398-day) validity. The shorter the validity period, the more frequently certificates must be renewed — automation is not optional at scale.

For Let’s Encrypt / Certbot:
sudo certbot renew --force-renewal
Then reload your web server: sudo systemctl reload nginx

For Cloudflare (Universal SSL):
Cloudflare auto-manages Universal SSL certificates. If a Cloudflare-proxied site shows a cert error, check Cloudflare dashboard → SSL/TLS → Edge Certificates for status. If “Active”, the error may be from the origin certificate, not the edge certificate.

For manually managed certificates:
Purchase/generate new certificate → deploy leaf cert + full intermediate chain to server → reload web server process → verify with openssl s_client -connect yourdomain.com:443

Certificate expiry is 100% preventable. Set up monitoring alerts at 30 days, 14 days, and 7 days before expiry. Use automated renewal (Let’s Encrypt certbot, Cloudflare’s managed SSL, AWS ACM with auto-renewal). An expired certificate causes complete site downtime for all HTTPS users and is among the most embarrassing and avoidable incidents in web operations. Check the monitoring guide for SSL expiry alert configuration.

NET::ERR_CERT_AUTHORITY_INVALID — Untrusted CA

NET::ERR_CERT_AUTHORITY_INVALID
Chrome Edge
Firefox: SEC_ERROR_UNKNOWN_ISSUER Safari: Safari Can't Verify the Identity

Signing CA is not trusted or certificate chain is incomplete

Root cause — Scenario A (Self-signed certificate): The certificate was generated without a CA (e.g., openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout key.pem -out cert.pem). Self-signed certificates are not signed by any CA in browsers’ trust stores — they are their own root, which browsers do not trust. Acceptable in local development environments; never acceptable in production.

Root cause — Scenario B (Incomplete certificate chain): The server sends only the leaf certificate without including the intermediate CA certificate(s). Browsers that have not previously cached the intermediate CA or cannot fetch it via the AIA extension display this error. This is the most common cause of this error in production environments. The certificate itself is valid; the server configuration is incomplete.

Root cause — Scenario C (Distrust event): The issuing CA has been distrusted by a browser vendor (e.g., Symantec certificates distrusted by Chrome in 2018). Any certificate issued by a distrusted CA displays this error regardless of validity period or chain completeness.

Verify the chain with OpenSSL:
openssl s_client -connect yourdomain.com:443 -showcerts 2>/dev/null | openssl x509 -noout -text | grep -A2 "Issuer\|Subject"

Find and download your CA’s intermediate certificate from your CA’s website. Concatenate leaf + intermediate into a single file (called a certificate bundle or fullchain):
cat yourdomain.crt intermediate.crt > fullchain.crt

For nginx: ssl_certificate /path/to/fullchain.crt;
For Apache: SSLCertificateChainFile /path/to/intermediate.crt
For Let’s Encrypt certbot: Use /etc/letsencrypt/live/domain/fullchain.pem (not cert.pem) — fullchain.pem includes the intermediate automatically.

NET::ERR_CERT_COMMON_NAME_INVALID — Hostname Mismatch

NET::ERR_CERT_COMMON_NAME_INVALID
Chrome Edge
Firefox: SSL_ERROR_BAD_CERT_DOMAIN Safari: Hostname Mismatch

The certificate’s Subject Alternative Names do not include the hostname being visited

Root cause: TLS certificate validation requires that the hostname in the browser’s address bar matches at least one entry in the certificate’s Subject Alternative Names (SAN) extension. Browsers stopped accepting the Common Name (CN) field for hostname matching in 2017 (Chrome 58) — only the SAN extension is checked. This error fires when: (1) visiting www.example.com but the certificate only covers example.com (or vice versa), (2) visiting a subdomain not included in the certificate, (3) after a domain migration where the old certificate is still in use, or (4) when using an IP address to access a server that only has a domain-based certificate.

Common misconfiguration: A certificate issued for example.com without the SAN www.example.com causes this error when users visit https://www.example.com. Modern CAs include both the root domain and www subdomain by default when issuing a certificate for example.com — but older certificates or certificates issued for only one name specifically will cause this.

Check what names the certificate covers:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -ext subjectAltName

Reissue the certificate including all required hostnames in the SAN field:
— For Let’s Encrypt: certbot certonly -d example.com -d www.example.com -d api.example.com
— Or use a wildcard certificate (*.example.com) to cover all first-level subdomains with a single certificate. Wildcards do not cover the root domain (example.com) — include it explicitly.
— For Cloudflare: Cloudflare’s Universal SSL automatically covers the root domain and one level of subdomains (example.com and *.example.com).

SSL_ERROR_RX_RECORD_TOO_LONG — HTTP on HTTPS Port

SSL_ERROR_RX_RECORD_TOO_LONG
Firefox
Chrome: ERR_SSL_PROTOCOL_ERROR Safari: Safari Can’t Connect Securely

The server is sending plain HTTP on port 443 (the HTTPS port)

Root cause: The browser sends a TLS ClientHello message (the first step of the TLS handshake) on port 443. The server responds with a plain HTTP response (e.g., an HTML redirect or an HTTP 301 response) instead of a TLS ServerHello. The browser, expecting TLS records, instead receives an HTTP response that begins with HTTP/1.1 — which, interpreted as a TLS record, appears to have a record length far exceeding the TLS maximum (which is why Firefox names it “record too long”).

This error indicates a server configuration problem where port 443 is not configured to speak TLS. Common causes: a virtual host on port 443 missing its SSL/TLS configuration directives, a load balancer forwarding HTTPS connections to a backend that expects plain HTTP without TLS, or a misconfigured nginx/Apache block that handles port 443 but lacks ssl on / listen 443 ssl.

For nginx — ensure port 443 has SSL configured:
listen 443 ssl; # not just 'listen 443;'
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;

For Apache:
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /path/to/cert.pem
SSLCertificateKeyFile /path/to/privkey.pem
</VirtualHost>

For load balancer setups: Ensure TLS is terminated at the load balancer (SSL offloading) or that the backend receives TLS-wrapped connections if end-to-end encryption is required. Never forward raw HTTPS connections to an HTTP-only backend.

Mixed Content Errors — HTTP Resources on HTTPS Pages

Mixed content occurs when an HTTPS page loads one or more resources (scripts, stylesheets, images, iframes, fonts) over plain HTTP rather than HTTPS. This breaks the security guarantee of HTTPS: even if the page itself is delivered over TLS, an HTTP resource can be intercepted and modified by a network attacker, potentially injecting malicious code into the page. Browsers address this by blocking or warning on mixed content, with the severity depending on the resource type.

Blocked (Active Mixed Content)

Scripts, Iframes, XMLHttpRequest

Scripts (<script src="http://...">), iframes (<iframe src="http://...">), and XHR/fetch requests to HTTP URLs are blocked entirely by all modern browsers. The resource is not loaded at all, which typically breaks page functionality.

The browser console shows: “Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure resource 'http://...'. This request has been blocked.”

Warning (Passive Mixed Content)

Images, Audio, Video

Images (<img src="http://...">), audio, and video loaded over HTTP are treated as passive mixed content. Older browsers display a warning in the address bar (downgraded padlock). Modern Chrome and Firefox have been progressively auto-upgrading these to HTTPS and blocking them if HTTPS is unavailable.

The page may visually appear broken (missing images) but is not completely non-functional. Console shows mixed content warnings.

The most common source of mixed content in production sites is a database migration from HTTP to HTTPS that did not update hardcoded URLs in the content database. WordPress sites moved from HTTP to HTTPS frequently have http:// URLs stored in the wp_posts table for images, links, and embedded media. The fix requires a search-and-replace across the database (wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' --all-tables) in addition to updating the siteurl and home options.

1. Content Security Policy header (auto-upgrade):
Content-Security-Policy: upgrade-insecure-requests
Instructs browsers to upgrade all HTTP resource requests to HTTPS automatically. Does not fix the underlying URLs but prevents mixed content errors for resources that are available over HTTPS.

2. HSTS (HTTP Strict Transport Security):
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Instructs browsers to always use HTTPS for this domain, preventing accidental HTTP navigation. Does not fix mixed content from external HTTP resources.

3. Find mixed content:
Open Chrome DevTools → Console tab. Filter by “Mixed Content”. All HTTP resource URLs will be listed. Alternatively use the open-source tool mixed-content-scanner to crawl your site and report all HTTP resources.

How to Check SSL Certificate Expiry Before It Expires

A proactive SSL certificate expiry check takes 10 seconds and prevents the most avoidable cause of HTTPS downtime. Set a recurring calendar reminder to run these checks, or configure your uptime monitoring tool to alert on certificate expiry — most tools (UptimeRobot, Better Uptime, Freshping) offer SSL certificate monitoring as a built-in feature alongside HTTP uptime checks.

Check expiry via OpenSSL (command line)
openssl s_client -connect yourdomain.com:443 \ -servername yourdomain.com < /dev/null 2>/dev/null \ | openssl x509 -noout -dates # Output: # notBefore=Jan 1 00:00:00 2026 GMT # notAfter=Dec 31 23:59:59 2026 GMT <-- this is your expiry date
Check days remaining (Linux/macOS one-liner)
echo | openssl s_client -connect yourdomain.com:443 \ -servername yourdomain.com 2>/dev/null \ | openssl x509 -noout -checkend 2592000 \ && echo "Valid for 30+ days" || echo "EXPIRES WITHIN 30 DAYS"
Check via curl (shows certificate info in verbose output)
curl -vI https://yourdomain.com 2>&1 | grep -A5 "start date\|expire date\|subject\|issuer"

The recommended expiry response timeline:

30 days

Initial alert — plan renewal

If using manual certificate management: begin the renewal process now. If using automated renewal (certbot, ACM): verify the automation is working and the next renewal is scheduled. 30 days provides ample time to troubleshoot any renewal issues without time pressure.

14 days

Escalated alert — act if not renewed

If the certificate has not been renewed by 14 days remaining, treat it as an incident. Manual renewal must happen now. Verify certbot cron jobs or ACM auto-renewal status. Check for any ACME validation failures in certbot logs (/var/log/letsencrypt/letsencrypt.log).

7 days

Critical alert — emergency renewal

7 days remaining is a P1 incident. Escalate immediately. Force renewal: certbot renew --force-renewal. If Let’s Encrypt ACME challenges are failing (DNS validation issues, firewall blocking port 80), switch validation method: use DNS challenge (--preferred-challenges dns) instead of HTTP challenge.

0 days

Expired — complete HTTPS downtime

All HTTPS traffic is blocked by browsers. Every user sees a certificate error page they cannot bypass (except by clicking through a security warning in some browsers). Revenue, SEO, and user trust impact begins immediately. If you reach this point, emergency renewal is the only fix — there is no grace period.

How DownCheck Monitors SSL Certificate Health

DownCheck captures SSL certificate metadata on every HTTPS probe, verifying that the certificate is valid and recording the days remaining until expiry alongside the HTTP status check. Every on-demand probe and scheduled monitoring check includes certificate validation as a parallel check to the HTTP response, giving you a real-time snapshot of both service availability and certificate health in a single request.

📅

Expiry Date Detection

Each HTTPS probe reads the notAfter field from the certificate presented during the TLS handshake and records the days remaining until expiry alongside the response time and HTTP status.

🔒

Chain Validation

The probe performs full TLS certificate chain validation — the same steps a browser performs. A certificate with an incomplete chain, an untrusted CA, or a hostname mismatch registers as a TLS failure alongside the HTTP response failure.

⚠️

Failure Classification

When an HTTPS probe fails, DownCheck distinguishes between HTTP failures (server returned an error status) and TLS failures (certificate validation failed before any HTTP response was possible), allowing faster diagnosis of the failure type.

The practical integration: when you check a domain on DownCheck and see the Cloudflare Edge probe failing with a TLS error while the Railway probe succeeds, this indicates a certificate mismatch between what Cloudflare is presenting at the edge and what your origin is serving — a common failure after deploying a new certificate to the origin without updating the Cloudflare-managed edge certificate, or when using strict SSL mode in Cloudflare with an invalid or expired origin certificate. Pair DownCheck’s on-demand TLS verification with your continuous uptime monitoring tool’s SSL expiry alerts for complete certificate lifecycle coverage.


SSL Error Quick Reference

Error CodeMeaningPrimary Fix
NET::ERR_CERT_DATE_INVALIDCertificate expired (notAfter date passed)Renew certificate and redeploy
NET::ERR_CERT_AUTHORITY_INVALIDUntrusted CA or incomplete certificate chainInstall full chain (leaf + intermediate)
NET::ERR_CERT_COMMON_NAME_INVALIDHostname not in certificate’s SANReissue cert with correct hostnames or use wildcard
SSL_ERROR_RX_RECORD_TOO_LONGPlain HTTP served on port 443Add SSL config to port 443 virtual host
ERR_SSL_PROTOCOL_ERRORTLS handshake failed (version/cipher mismatch)Enable TLS 1.2/1.3, update cipher suites
ERR_SSL_VERSION_OR_CIPHER_MISMATCHNo shared TLS version or cipher between client/serverEnable TLS 1.2 minimum; remove SSL 3.0, TLS 1.0/1.1
Mixed Content (Active)HTTPS page loading HTTP scripts or iframesUpdate resource URLs to HTTPS; add CSP upgrade-insecure-requests
ERR_CERT_REVOKEDCertificate revoked by issuing CA (compromise or mis-issuance)Obtain new certificate immediately; revoke compromised private key

Frequently Asked Questions

What causes SSL certificate errors?
SSL certificate errors occur when the browser’s TLS validation fails for one of four reasons: (1) expired certificate (notAfter date passed), (2) untrusted CA or incomplete certificate chain, (3) hostname mismatch (SAN doesn’t include the visited hostname), or (4) server sending plain HTTP on the HTTPS port. Each produces a distinct browser error code identifying which check failed.
What is NET::ERR_CERT_DATE_INVALID?
NET::ERR_CERT_DATE_INVALID means the TLS certificate has passed its notAfter expiry date. Browsers check validity against current time on every connection and reject expired certificates instantly. The fix is to renew the certificate and deploy it to the server — sudo certbot renew --force-renewal for Let’s Encrypt, or re-issue from your commercial CA.
What is NET::ERR_CERT_AUTHORITY_INVALID?
NET::ERR_CERT_AUTHORITY_INVALID means the certificate was signed by a CA not in the browser’s trusted root store, or the server is not sending the intermediate CA certificate(s) needed to complete the trust chain. The most common fix is deploying a fullchain certificate file (leaf + intermediate) rather than just the leaf certificate alone.
What is NET::ERR_CERT_COMMON_NAME_INVALID?
NET::ERR_CERT_COMMON_NAME_INVALID means the hostname you’re visiting is not listed in the certificate’s Subject Alternative Names (SAN) extension. Reissue the certificate including all required hostnames, or use a wildcard certificate (*.yourdomain.com) to cover all first-level subdomains. Note that wildcards do not cover the root domain — include it explicitly.
What is mixed content and how does it cause SSL warnings?
Mixed content occurs when an HTTPS page loads resources over plain HTTP. Browsers block active mixed content (scripts, iframes) entirely and warn on passive mixed content (images). Fix by updating resource URLs to HTTPS, adding the Content-Security-Policy: upgrade-insecure-requests header, or running a database search-and-replace to update hardcoded HTTP URLs to HTTPS.
How do I check when my SSL certificate expires?
Command line: openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null 2>/dev/null | openssl x509 -noout -dates. Browser: click the padlock icon → Certificate is valid → view Valid Until date. Online: SSL Labs (ssllabs.com/ssltest). Set monitoring alerts at 30, 14, and 7 days before expiry.

Check SSL certificate health now

DownCheck validates TLS certificate chain, hostname match, and expiry date as part of every HTTPS probe — alongside the HTTP status and response time check.

Check a site →