Expired or invalid certificate: reading the error and fixing it
A practical guide to understanding the four browser certificate errors, finding the cause with openssl, and fixing it with certbot, on Ubuntu/Nginx or cPanel/Plesk.
UptimeMag editorial team · 10 October 2026 · 6 min read

The quickest check, before reading anything else
Site down, certificate error on the homepage. The first thing to run, from any terminal (you don't need to be on the server):
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com -showcerts </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
This command connects on port 443 just as a browser would, and prints who the certificate is issued to, who signed it, and its validity dates (notBefore/notAfter). This is the certificate the server is actually serving right now, not the one you think you installed: if you renewed yesterday but you're still seeing the old date here, the problem isn't the certificate — it's that Nginx or Apache hasn't reloaded it.
The four browser messages, and what they mean
| Typical browser message | What it's telling you | Most common cause |
|---|---|---|
| NET::ERR_CERT_DATE_INVALID / "The certificate has expired" | Today's date falls outside the certificate's notBefore/notAfter range | Automatic renewal didn't run or failed |
| NET::ERR_CERT_COMMON_NAME_INVALID / "The name doesn't match" | The domain in the address bar isn't among those listed on the certificate (Subject Alternative Name) | Certificate was requested for a different domain/subdomain, or the www variant is missing |
| "Incomplete certificate chain" / warning on some devices only | The server isn't sending the intermediate certificate, only the leaf one | Server configuration serving only cert.pem instead of the fullchain |
| NET::ERR_CERT_AUTHORITY_INVALID / "Authority not recognised" | The certificate is signed by a CA that the device doesn't have among its trusted roots | Self-signed certificate, expired CA (see the IdenTrust/Let's Encrypt case), or an outdated root store on the client |
For non-sysadmins: the browser is only checking three things, in order — that the certificate hasn't expired, that it's issued to the correct site, and that it's signed by someone your computer trusts all the way up the chain. If any one of these three doesn't check out, the page gets blocked.
Cause 1: expired certificate
How to tell if this is yours. Look at the output of the command above: the notAfter= line must show a future date. If it's in the past, this is your cause.
How to fix it (Ubuntu 24.04, Nginx, Certbot).
sudo certbot certificates
This lists the certificates managed by Certbot along with their expiry dates. If the one for the domain in error has expired or is close to expiring, force a renewal:
sudo certbot renew --cert-name yourdomain.com --force-renewal
sudo systemctl reload nginx
The second command is the one that's often missing: Certbot renews the file on disk but doesn't restart the web service on its own, unless you've set up a deploy-hook.
On cPanel. In the SSL/TLS Status section of WHM/cPanel you can see the expiry date for each domain and force "Run AutoSSL" on the domain in question.
On Plesk. Under "Websites & Domains" → domain → "SSL/TLS Certificates" you can see the expiry date, and there's a button to renew manually.
Cause 2: name mismatch
How to tell. In the same openssl output, look for the subject= line, and if you want to see all the names covered, use:
openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -noout -text | grep -A1 "Subject Alternative Name"
If the domain you're visiting (e.g. www.yourdomain.com) doesn't appear in that list, this is the cause.
How to fix it. Reissue the request including all the names you need:
sudo certbot certonly --nginx -d yourdomain.com -d www.yourdomain.com
Certbot overwrites the existing certificate with a new one covering both names.
Cause 3: incomplete certificate chain
This is the sneakiest error because on desktop Chrome it often doesn't show up (the browser caches intermediates), but it fails on smartphones, API clients, curl, or external SSL scanners.
How to tell if this is yours. In the output of openssl s_client -showcerts, count how many BEGIN CERTIFICATE blocks you see. If there's only one, the server is sending only the leaf certificate without the intermediate. The fullchain must always be served, not the certificate on its own.
How to fix it (Nginx). In the server block, check that the directive points to the fullchain file, not the single certificate:
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
With Certbot, fullchain.pem already contains the certificate plus the intermediate: if the configuration shows cert.pem instead of fullchain.pem, that's the mistake. After fixing it:
sudo nginx -t && sudo systemctl reload nginx
On Apache. The directive to check is SSLCertificateFile, which must also point to fullchain.pem; from version 2.4.8 onwards, Apache no longer requires a separate directive for the chain.
Cause 4: authority not recognised
How to tell. In the openssl output, the issuer= line shows who signed the certificate. If it's a name you don't recognise (an internal CA, a corporate proxy) or if the certificate is self-signed (subject and issuer match), the visitor's device has no reason to trust it.
How to fix it. If it's a self-signed certificate left on production by mistake, it needs replacing with one issued by a public CA: same command as Cause 1, certbot certonly --nginx -d yourdomain.com. If, on the other hand, the certificate is correct but the error only appears on older devices, it's a client-side root store issue, not a server one: there's nothing to fix on the hosting side, and it should be flagged to the user instead.
The "I renewed it but the browser still sees the old one" case
This almost always comes down to one of these three reasons, in order of frequency:
- The web service hasn't been reloaded. Certbot writes the new file to
/etc/letsencrypt/live/yourdomain.com/, but Nginx/Apache keep the old certificate in memory until they're reloaded. Check withsudo systemctl status nginxthat there are no errors, then runsudo systemctl reload nginx. - A reverse proxy or CDN in front of the server (e.g. Cloudflare, a load balancer) is still serving a cached copy of the previous certificate. In this case the problem isn't on your server: you need to clear the cache on the proxy side or wait for the TTL to expire.
- The wrong virtual host. The domain in error is being served by a different
serverblock from the one you updated (this happens when multiple sites run on the same machine). Check withsudo nginx -T | grep -A5 server_nameto see which block is responding for that name.
How to automate renewal and avoid ending up here again in 90 days
Let's Encrypt issues short-lived certificates, which is why automatic renewal is needed. Certbot includes a cron job or a systemd timer that renews certificates automatically before they expire, so you normally don't need to run the command manually. To check that the mechanism is actually working, without touching the certificate in production:
sudo certbot renew --dry-run
On Ubuntu with systemd, the timer is managed automatically by the package; to check whether it's active:
systemctl list-timers | grep certbot
If the system still uses cron instead of systemd, the job is located at /etc/cron.d/certbot; according to the documentation, this cron job does NOT run if systemd is in use as the init system: in that case, the timer takes precedence.
If the problem lies with the provider, not with you
If the domain is on shared hosting with a control panel (cPanel with AutoSSL, Plesk with integrated Let's Encrypt) and the certificate won't renew despite everything appearing correct on the DNS side, the problem may be on the provider's end: port 80 blocked for HTTP validation, an account rate limit, or a panel bug following an update. In this case, open a support ticket attaching:
- the full output of
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com -showcerts; - the output of
sudo certbot certificates(or a screenshot of the panel's SSL section); - the exact time you attempted the renewal, so the technician can cross-reference the logs.
Without these three pieces of information, first-line support will waste time asking you for them, and the site will stay down for longer.
Written with the help of artificial intelligence and checked by the editors (EU AI Act, art. 50).