Certificate Has Expired: How to Fix It on Any Platform

Seeing 'certificate has expired' on a site? Confirm it with one command, then renew on certbot, cPanel, Plesk, Cloudflare, IIS, or a managed host.

“Certificate has expired” is the one SSL error that is never a false alarm. Browsers, curl, mail clients, and mobile apps all say the same thing in slightly different words, and they all mean the same fact: the server presented a certificate whose notAfter date is in the past. This guide gets the site back up first, then covers the fix for each hosting setup you are likely to meet.

What the error looks like

The wording depends on what hit the expired certificate:

Where you see it Message
Chrome / Edge “Your connection is not private” with NET::ERR_CERT_DATE_INVALID
Firefox “Warning: Potential Security Risk Ahead” with SEC_ERROR_EXPIRED_CERTIFICATE
Safari “This Connection Is Not Private” — certificate expired
curl curl: (60) SSL certificate problem: certificate has expired
openssl Verify return code: 10 (certificate has expired)
Python requests SSLError: certificate verify failed: certificate has expired
Java CertificateExpiredException: NotAfter: ...
Mail clients “The server’s security certificate has expired”

If you got here from a Chrome error, the NET::ERR_CERT_DATE_INVALID guide covers the visitor-side causes too. If it came from a script or CI job, see curl (60) certificate has expired, because the fix there is often on the client, not the server. If what you are looking at is the red browser warning page itself, Your Connection Is Not Private decodes the error code printed under the headline and tells a site problem from a device problem; when the warning appears on every website you open, the cause is your own clock, network, or security software rather than the sites.

Step 1: Confirm which certificate expired

Do not trust the browser alone. Browsers cache certificates, corporate proxies swap them, and a CDN can serve a different certificate from the one on your origin. Ask the server directly:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

You will get notBefore, notAfter, the subject, and the issuer. Three things to read off it:

  • notAfter in the past — the leaf certificate expired. Continue to step 2.
  • notAfter in the future but the browser still complains — an intermediate in the chain expired, or the client’s clock is wrong. Run the full chain check below.
  • Subject is not your domain — you are hitting a default virtual host or a load balancer with the wrong certificate. That is a configuration problem, not an expiry problem.

To see the whole chain that the server sends:

echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>/dev/null \
  | grep -E "s:|i:|NotAfter|Verify return"

If you would rather not use a terminal, the SSL certificate checker shows the served certificate, its chain, and days remaining from a URL.

Step 2: Renew on your platform

Pick the section that matches where the certificate lives. When in doubt, the issuer line from step 1 tells you: “Let’s Encrypt” usually means certbot or a hosting panel’s auto-SSL, “Cloudflare” means the edge certificate, “Sectigo” or “DigiCert” usually means a purchased certificate installed by hand.

certbot on a Linux server (Nginx or Apache)

sudo certbot renew --force-renewal
sudo systemctl reload nginx     # or apache2

If renewal fails, request a new certificate instead of debugging under pressure:

sudo certbot certonly --nginx -d example.com -d www.example.com

Common reasons certbot renew fails:

  • HTTP-01 challenge cannot reach the server. DNS changed, a firewall now blocks port 80, or the site sits behind a proxy that does not forward /.well-known/acme-challenge/. Check with curl -I http://example.com/.well-known/acme-challenge/test from outside.
  • A CAA record forbids Let’s Encrypt. dig CAA example.com should either return nothing or include letsencrypt.org.
  • Rate limits. Too many issuances for the same names in the last week. The error message says so explicitly; wait or use the staging environment to test.
  • The timer is dead. systemctl list-timers | grep certbot should show a scheduled run. If not: sudo systemctl enable --now certbot.timer.

After a successful renewal, re-run the openssl check from step 1. If the old date still shows, the server did not reload. Add a deploy hook so it reloads automatically next time:

# /etc/letsencrypt/renewal/example.com.conf
renew_hook = systemctl reload nginx

cPanel

Security → SSL/TLS Status → tick the domain → Run AutoSSL. Wait a few minutes and check the status column. If AutoSSL reports a DCV (domain control validation) failure, the most common causes are a .htaccess redirect that sends /.well-known/ to HTTPS or a CDN in front of the origin. Temporarily exclude /.well-known/ from the redirect and rerun.

For a purchased certificate, SSL/TLS → Manage SSL sites → install the new certificate, bundle, and key for the domain.

Plesk

Websites & Domains → the domain → SSL/TLS Certificates. For Let’s Encrypt, click Reissue or Renew. If the “Keep websites secured” extension is installed, it should have renewed automatically; check its log under Tools & Settings for the reason it did not. For a purchased certificate, upload the new certificate in the same panel and select it for the domain.

Cloudflare

If the site is proxied (orange cloud), visitors see Cloudflare’s edge certificate, not yours. Universal SSL renews on its own, but it can fail when:

  • the domain’s nameservers were recently changed away from Cloudflare;
  • a CAA record excludes Cloudflare’s certificate authorities; or
  • the zone is paused.

Check SSL/TLS → Edge Certificates for the status. If the browser error mentions your origin’s certificate, your SSL mode is Full (strict) and the origin certificate expired. Either renew it with certbot as above, or replace it with a Cloudflare Origin CA certificate (valid up to 15 years) under SSL/TLS → Origin Server.

Windows Server / IIS

Open IIS Manager → server node → Server Certificates. Expired certificates show their expiry date. Either Renew (creates a renewal request for a purchased certificate) or install a new certificate, then update the HTTPS binding: Sites → the site → Bindings → https → select the new certificate. Restart the site, not the whole server.

If you use win-acme or Certify The Web for Let’s Encrypt, open the client and force a renewal there; the scheduled task that runs renewals is frequently the thing that broke after a server reboot or password change.

Managed platforms (Vercel, Netlify, Render, Railway, Fly)

These renew automatically and rarely fail. When they do, it is almost always because DNS no longer points at the platform, or the domain was removed and re-added. Open the project’s domain settings; there is a per-domain status with a Renew or Retry action. If the domain shows as unverified, fix the DNS record it asks for and retry.

Purchased certificates (DigiCert, Sectigo, GoDaddy, etc.)

You need to buy or renew through the vendor, complete validation again, download the new certificate plus intermediate bundle, and install both. The most common installation mistake after a renewal is forgetting the intermediate. The site then works in a browser that has the intermediate cached and fails everywhere else. Verify with the -showcerts command above that the server sends the full chain.

If the warning is coming from a NAS admin panel rather than a public site, the self-signed default certificate is the culprit; the TrueNAS “certificate freenas_default has expired” fix walks through replacing it.

Step 3: Verify from outside your network

Once you believe it is fixed, check from somewhere that is not your machine. Your browser may still be caching the old session, and if the site sits behind a CDN, the edge you are hitting may lag behind the others. Use the openssl command from a different server, or run the website checker, which connects from an independent location and reports the served certificate.

Why “it auto-renews” still fails

Almost every expired certificate we see belongs to a site whose owner believed renewal was automatic. It was, until something changed: a DNS migration broke the challenge, a rebuilt server lost the timer, a CAA record was added for compliance, or the certificate renewed on the origin while a proxy kept serving the old one. The long version of that list, with the commands to diagnose each one, is in why your SSL certificate expired without warning.

The fix for the pattern, rather than the incident, is to check the served certificate on a schedule and alert on days remaining. Let’s Encrypt certificates last 90 days today, and the industry is moving to much shorter lifetimes over the next few years, so the window for a silent failure only gets narrower. SitesRadar’s free plan monitors one site’s SSL expiry, uptime, broken links, and DNS, and emails you at 30, 14, and 7 days out. For a full process across several client sites, read the guide to SSL certificate expiration monitoring.

FAQ

The certificate renewed but visitors still see the error. Why? The server has not reloaded, a CDN is serving a cached certificate, or visitors have an old tab open. Reload the web server, purge or check the CDN, and verify with openssl from outside.

Can I just tell visitors to click “proceed anyway”? No. Modern browsers hide that option for HSTS sites, mobile apps will refuse outright, and every visitor who sees the warning has just been told your site is unsafe. Fix the certificate.

How long does a renewal take to propagate? There is no propagation for a certificate on a single server: the next connection after the reload gets the new one. Behind a CDN, edges pick up a new certificate within minutes. Anything longer means a cache or a wrong origin.

The certificate says it expires next month. Why is the error already showing? Check the client’s clock, and check the intermediate certificate. An intermediate that expired takes every leaf under it down with it, even though the leaf’s own dates look fine.

← More from the SitesRadar blog