To check when a certificate expires, run echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -enddate — it prints the notAfter (expiry) date for the live certificate. For a local file, use openssl x509 -in cert.pem -noout -enddate; for a quick visual check, click the browser padlock and read "Valid to"; and for scripts, openssl x509 -noout -checkend 2592000 exits non-zero if the certificate expires within the next 30 days. The reliable pattern for production is to check remotely with s_client, compare against your alert thresholds (30, 14, 7, 1 days), and let automated renewal do the actual work.
That's the summary an AI Overview gives you. What it can't give you is the decision of which method to use for which situation, the exact one-liners that survive copy-paste, or the reason this is about to get much harder: certificate lifetimes are shrinking to 47 days by 2029, which makes manual checking obsolete and automation mandatory. This guide covers all of it.
How to Check Certificate Expiration: Every Method Compared
There is no single "right" way to check a certificate's expiry date — the best tool depends on whether you have shell access, a local file, or need continuous alerting. This table maps each method to the situation it fits, with a copy-paste command for each.
| Method | Command / How | Best for | Notes |
|---|---|---|---|
| Browser padlock | Click the padlock → Certificate (or "Connection is secure" → "Certificate is valid") → read Valid to | A quick one-off visual check | No CLI needed; browser may show local time, not UTC |
| openssl x509 (local file) | openssl x509 -in cert.pem -noout -enddate | A certificate file already on disk | Add -dates to see both notBefore and notAfter |
| openssl s_client (live server) | echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -enddate | Checking what's actually deployed on an endpoint | -servername sends SNI (required for multi-cert hosts) |
| curl -vI | curl -vI https://example.com 2>&1 | grep "expire date" | A fast check with a tool you already have | Reads curl's own verbose TLS output; no OpenSSL needed |
| openssl -checkend (scripts) | echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -checkend 2592000 | Cron / CI gating | Exit code 1 if it expires within 2,592,000s (30 days); 0 if still valid |
| Online checker | Paste the hostname into an SSL checker (SSL Labs, or the tool below) | No shell access, or sharing a shareable report | Reads the public endpoint; can also flag chain/protocol issues |
| Monitoring platform | Datadog / UptimeRobot / Pingdom, Prometheus ssl_exporter, or cert-manager metrics | Continuous alerting across many hosts | The only option that scales; alerts at configurable thresholds |
Which should I use? For a one-off human check, the browser padlock or curl -vI. For scripting and CI, openssl ... -checkend. For production fleets, a monitoring platform is the only answer that scales — and with 47-day certificates arriving (see below), it's no longer optional.
The Importance of Certificate Expiration Monitoring
When an SSL/TLS certificate expires, HTTPS connections fail. Browsers display security warnings, users can't access the site, and services relying on HTTPS are disrupted. Despite this serious consequence, certificate expiration remains one of the most common causes of unexpected downtime in production systems. Many organizations have experienced the embarrassment of a high-profile service going down because someone forgot to renew a certificate.
Preventing certificate expiration problems requires both automated monitoring and renewal processes. You need to know well in advance when certificates will expire so you have time to renew them, and you need systems in place to automatically check expiration dates and alert you before it's too late.
Manual Certificate Expiration Checking
Using OpenSSL:
# Check expiration of a certificate file
openssl x509 -in certificate.crt -noout -dates
# Output:
# notBefore=Jan 15 12:34:56 2024 GMT
# notAfter=Apr 14 12:34:56 2024 GMT
# Extract just the expiration date
openssl x509 -in certificate.crt -noout -enddate
# Output:
# notAfter=Apr 14 12:34:56 2024 GMT
Checking a live HTTPS server's certificate:
# Connect to server and retrieve certificate
openssl s_client -connect example.com:443 -servername example.com < /dev/null | openssl x509 -noout -dates
# For just the expiration date:
openssl s_client -connect example.com:443 -servername example.com < /dev/null | openssl x509 -noout -enddate
Using curl:
# Check certificate expiration from a URL
curl -vI https://example.com 2>&1 | grep "expire date"
# Output:
# * expire date: Apr 14 12:34:56 2024 GMT
Using Python:
from datetime import datetime
import ssl
def check_certificate_expiration(hostname, port=443):
context = ssl.create_default_context()
try:
with context.create_connection((hostname, port), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
expiration = datetime.strptime(
cert['notAfter'],
'%b %d %H:%M:%S %Y %Z'
)
days_until_expiration = (expiration - datetime.now()).days
print(f"Certificate expires: {expiration}")
print(f"Days until expiration: {days_until_expiration}")
if days_until_expiration < 0:
print("CRITICAL: Certificate is EXPIRED")
elif days_until_expiration < 30:
print(f"WARNING: Certificate expires in {days_until_expiration} days")
else:
print(f"OK: Certificate is valid for {days_until_expiration} more days")
return expiration, days_until_expiration
except Exception as e:
print(f"Error checking certificate: {e}")
return None, None
# Usage
check_certificate_expiration('example.com')
Using JavaScript (Node.js):
const https = require('https');
const tls = require('tls');
function checkCertificateExpiration(hostname) {
const options = {
hostname: hostname,
port: 443,
method: 'HEAD'
};
const req = https.request(options, (res) => {
const cert = res.socket.getPeerCertificate();
const expirationDate = new Date(cert.valid_to);
const now = new Date();
const daysUntilExpiration = Math.floor((expirationDate - now) / (1000 * 60 * 60 * 24));
console.log(`Certificate expires: ${expirationDate}`);
console.log(`Days until expiration: ${daysUntilExpiration}`);
if (daysUntilExpiration < 0) {
console.log('CRITICAL: Certificate is EXPIRED');
} else if (daysUntilExpiration < 30) {
console.log(`WARNING: Certificate expires in ${daysUntilExpiration} days`);
} else {
console.log(`OK: Certificate is valid for ${daysUntilExpiration} more days`);
}
res.resume();
});
req.on('error', (err) => {
console.error(`Error checking certificate: ${err.message}`);
});
req.end();
}
// Usage
checkCertificateExpiration('example.com');
Automated Certificate Expiration Monitoring
For production systems, manual checking isn't sufficient. You need automated monitoring that regularly checks expiration dates and alerts you before expiration.
Monitoring Tools:
- Uptime/Monitoring Services:
- Uptimerobot
- Pingdom
- New Relic
- Datadog
These services monitor HTTPS endpoints and can alert when certificate expiration is approaching (typically configurable for 30, 14, 7, and 1-day warnings).
- Certificate Management Tools:
- Sectigo (formerly Comodo)
- DigiCert
- GlobalSign
Most commercial CA platforms offer monitoring and automated renewal.
-
Open Source Tools:
- Certbot (from Let's Encrypt)
- Acme.sh
- cert-manager (Kubernetes)
-
Custom Scripts: Create monitoring scripts that check certificates on a schedule.
Example Monitoring Script (Bash):
#!/bin/bash
HOSTNAME="example.com"
ALERT_THRESHOLD_DAYS=30
EMAIL_ALERT="admin@example.com"
# Get certificate expiration date
EXPIRATION=$(echo | openssl s_client -servername $HOSTNAME -connect $HOSTNAME:443 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
# Convert to seconds since epoch
EXPIRATION_EPOCH=$(date -d "$EXPIRATION" +%s)
NOW_EPOCH=$(date +%s)
# Calculate days until expiration
DAYS_UNTIL=$((($EXPIRATION_EPOCH - $NOW_EPOCH) / 86400))
# Check and alert
if [ $DAYS_UNTIL -lt 0 ]; then
echo "CRITICAL: Certificate for $HOSTNAME is EXPIRED" | mail -s "CRITICAL: Certificate Expired" $EMAIL_ALERT
elif [ $DAYS_UNTIL -lt $ALERT_THRESHOLD_DAYS ]; then
echo "WARNING: Certificate for $HOSTNAME expires in $DAYS_UNTIL days" | mail -s "WARNING: Certificate Expiring" $EMAIL_ALERT
else
echo "OK: Certificate for $HOSTNAME is valid for $DAYS_UNTIL more days"
fi
Add this to cron to run regularly:
# Check certificate expiration daily
0 9 * * * /path/to/check_cert_expiration.sh
Example Monitoring with Prometheus (Node Exporter):
The Node Exporter has a textfile_collector that can run scripts reporting metrics.
Create a script that outputs Prometheus metrics:
#!/bin/bash
HOSTNAME="example.com"
# Get certificate expiration in Unix timestamp
EXPIRATION=$(echo | openssl s_client -servername $HOSTNAME -connect $HOSTNAME:443 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
EXPIRATION_EPOCH=$(date -d "$EXPIRATION" +%s)
# Output Prometheus metric
echo "# HELP certificate_expires_seconds_unix Certificate expiration time in Unix epoch"
echo "# TYPE certificate_expires_seconds_unix gauge"
echo "certificate_expires_seconds_unix{hostname=\"$HOSTNAME\"} $EXPIRATION_EPOCH"
Then Prometheus can alert when the expiration time is approaching:
groups:
- name: certificates
rules:
- alert: CertificateExpiresSoon
expr: (certificate_expires_seconds_unix - time()) / 86400 < 30
for: 1h
annotations:
summary: "Certificate expires in less than 30 days"
Kubernetes Certificate Monitoring
For Kubernetes clusters, certificate expiration is a common operational challenge:
Using cert-manager:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-cert
spec:
secretName: example-tls
issuerRef:
name: letsencrypt-prod
dnsNames:
- example.com
- www.example.com
# Auto-renew 30 days before expiration
renewBefore: 720h # 30 days
Monitoring with Prometheus:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: certificate-alerts
spec:
groups:
- name: certificates
interval: 30s
rules:
- alert: KubernetesCertificateExpiresSoon
expr: certmanager_certificate_renewal_errors_total > 0
for: 1h
annotations:
summary: "Certificate renewal error detected"
- alert: KubernetesCertificateExpires
expr: certmanager_certificate_expiration_timestamp_seconds - time() < 604800
# Triggers 7 days before expiration
for: 1h
annotations:
summary: "Certificate expires in less than 7 days"
Automated Certificate Renewal
Prevention is better than cure. Use automated renewal instead of manual renewal:
Let's Encrypt with Certbot:
# Install certbot
apt-get install certbot python3-certbot-nginx
# Get certificate
certbot certonly --nginx -d example.com -d www.example.com
# Set up auto-renewal (installed by default)
systemctl enable certbot.timer
systemctl start certbot.timer
# Check renewal status
certbot renew --dry-run
Certbot automatically renews certificates 30 days before expiration.
Docker-based Renewal:
FROM certbot/certbot
WORKDIR /etc/letsencrypt
VOLUME /etc/letsencrypt
ENTRYPOINT ["certbot", "renew", "--webroot", "-w", "/var/www/html"]
Run as a cron job:
docker run --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/www/html:/var/www/html \
certbot/certbot \
renew
Why This Gets Harder: 47-Day Certificates by 2029
In April 2025 the CA/Browser Forum passed Ballot SC-081v3 (29 votes in favour, zero against), committing every publicly trusted CA to a phased reduction of the maximum TLS certificate lifetime from today's 398 days down to 47 days by March 15, 2029. The domain-validation reuse window shrinks alongside it, so you re-prove control of your domain far more often too.
| Effective date | Max certificate lifetime | Max domain-validation reuse |
|---|---|---|
| Now (through Mar 2026) | 398 days | 398 days |
| March 15, 2026 | 200 days | 200 days |
| March 15, 2027 | 100 days | 100 days |
| March 15, 2029 | 47 days | 10 days |
<rect x="40" y="130" width="0" height="30" rx="6" fill="#2813e8">
<animate attributeName="width" values="0;301" dur="1.2s" begin="0.2s" fill="freeze"/>
</rect>
<text x="355" y="151" font-size="14" font-weight="700" fill="#0f172a">200 · Mar 2026</text>
<rect x="40" y="170" width="0" height="30" rx="6" fill="#f59e0b">
<animate attributeName="width" values="0;151" dur="1.2s" begin="0.4s" fill="freeze"/>
</rect>
<text x="205" y="191" font-size="14" font-weight="700" fill="#0f172a">100 · Mar 2027</text>
<rect x="40" y="210" width="0" height="30" rx="6" fill="#dc2626">
<animate attributeName="width" values="0;71" dur="1.2s" begin="0.6s" fill="freeze"/>
</rect>
<text x="125" y="231" font-size="14" font-weight="700" fill="#0f172a">47 · Mar 2029</text>
At a 47-day lifetime you would need to renew roughly every six weeks — far too often to survive on calendar reminders or a spreadsheet. The practical consequence is simple: manual renewal stops being viable and ACME-based automation (Let's Encrypt/Certbot, cert-manager, or your CA's ACME endpoint) becomes the only sustainable model. Start migrating any manually renewed certificate to automated issuance now, well before the 2026 cutover forces the issue.
Monitoring Across an Organization
For enterprises with many certificates:
Certificate Inventory: Maintain a database of all certificates:
- Hostname
- Certificate authority
- Expiration date
- Renewal date
- Owner contact
Centralized Monitoring: Use CMDB (Configuration Management Database) tools:
- Splunk
- ServiceNow
- Custom dashboard
Alerting Strategy: Set up alerts at multiple thresholds:
- 90 days before expiration: Info
- 30 days before expiration: Warning
- 7 days before expiration: Critical alert to responsible team
- Expired: Critical incident
Reporting: Generate monthly reports of certificate status across the organization.
Troubleshooting Certificate Expiration Issues
Problem: Certificate Shows as Expired but Browser Accepts It:
Likely cause: Your system time is incorrect. Certificates are time-based.
Solution: Sync system time: ntpdate -s time.nist.gov
Problem: Certificate Renewal Failed: Causes:
- DNS not pointing to verification server
- Firewall blocking challenge port
- Disk space exhausted
Solution: Check renewal logs and DNS configuration.
Problem: Intermediate Certificate Missing: If the certificate chain is incomplete, browsers may reject it. Solution: Include intermediate certificate in certificate bundle.
Best Practices
- Automate everything: Use Let's Encrypt and certbot or equivalent for automatic renewal
- Multiple alert levels: Alert progressively as expiration approaches
- Test renewal: Regularly test that renewal processes work
- Monitor across your entire organization: Know every certificate you operate
- Use DNS-based validation: More reliable than HTTP validation
- Plan for shrinking lifetimes: Maximum validity drops to 200 days in March 2026, 100 days in 2027, and 47 days in 2029 — assume renewal will be too frequent to do by hand and move to ACME automation now
Conclusion
Certificate expiration doesn't have to cause downtime. With proper monitoring (automated checking at multiple thresholds), automated renewal (using Let's Encrypt or similar), and good organizational practices (maintaining certificate inventory, understanding the renewal process), you can ensure your certificates never unexpectedly expire. The best approach is to fully automate both monitoring and renewal, treating certificate management as a solved technical problem rather than a manual operational burden.