By David Kim · Nov 7, 2025

What Happens Inside a TLS Handshake When Your Certificate Expires

Have you ever wondered what actually happens at the protocol level when a browser shows "Your connection is not private"? Most people see the warning as a binary event: certificate valid, site works; certificate expired, site broken. But the reality involves a precise sequence of cryptographic operations that occur within the first 200 milliseconds of every HTTPS connection. Understanding this sequence explains why expired certificates break things so completely, why some clients fail while others appear to work, and why automation tools like Let's Encrypt can silently fail without anyone noticing until the damage is done.

This article walks through the TLS handshake step by step, examines exactly where certificate expiry causes the handshake to abort, explains how the ACME protocol automates renewal, and identifies the specific failure modes that cause automated renewal to fail silently. Every section points to a concrete monitoring action that prevents the failure from reaching your users.

The TLS 1.3 Handshake: What Happens in Those First 200 Milliseconds

Before a single byte of your web page reaches the browser, the client and server must complete a TLS handshake. In TLS 1.3 (the current standard, defined in RFC 8446), this handshake takes one round trip (1-RTT) for new connections. Here is what happens at each step.

Step 1: ClientHello (client to server)

The client sends a ClientHello message containing its supported TLS versions, a list of cipher suites it can use, a random nonce, and key share entries for one or more key exchange groups (typically X25519 and P-256). In TLS 1.3, the client speculatively generates ephemeral key pairs and includes the public halves in the ClientHello, allowing the server to complete key exchange in its first response. The message also includes the Server Name Indication (SNI) extension, which tells the server which hostname the client is trying to reach. This is how a single IP address can serve certificates for multiple domains.

Step 2: ServerHello + EncryptedExtensions + Certificate + CertificateVerify + Finished (server to client)

The server responds with a ServerHello (selecting the cipher suite and key share), followed by a series of encrypted messages. After the ServerHello, all subsequent handshake messages are encrypted using keys derived from the shared secret. The server sends its certificate chain, a CertificateVerify signature proving it holds the private key, and a Finished message containing a MAC over the entire handshake transcript. In TLS 1.3, these all arrive in a single flight.

Step 3: Client validates the certificate chain

This is where expiry matters. The client performs a series of checks on the server's certificate chain, and if any check fails, the handshake is aborted. The validation sequence is roughly:

  1. Chain building: The client constructs a path from the leaf (server) certificate through zero or more intermediate certificates to a root CA in the client's trust store.
  2. Signature verification: Each certificate in the chain is verified against the public key of the certificate above it. The leaf is signed by the intermediate, the intermediate by the root.
  3. Validity period check: For each certificate in the chain, the client checks that the current time falls between the notBefore and notAfter timestamps. This is the check that fails when a certificate expires.
  4. Name matching: The client verifies that the leaf certificate's Subject Alternative Name (SAN) field contains the hostname from the SNI extension.
  5. Revocation check: Depending on the client configuration, a CRL or OCSP check may be performed to verify the certificate has not been revoked before expiry. Browsers increasingly use OCSP stapling (where the server includes a signed OCSP response) or CRLSets (precompiled revocation lists).
  6. Key usage and extended key usage: The certificate must have the correct key usage flags (digitalSignature for TLS 1.3) and the id-kp-serverAuth extended key usage.

What happens when the validity check fails

If the certificate's notAfter timestamp is in the past, the client sends a TLS alert message with level "fatal" and description "certificate_expired" (alert code 45), then closes the TCP connection. The connection is terminated at the TLS layer before any HTTP data is exchanged. The browser renders its security interstitial page, and the user sees "NET::ERR_CERT_DATE_INVALID" (Chrome), "SEC_ERROR_EXPIRED_CERTIFICATE" (Firefox), or a similar error.

There is an important subtlety here: the expiry check applies to every certificate in the chain, not just the leaf. If an intermediate certificate expires (which happens rarely but does happen), the chain validation fails even though the leaf certificate's dates are valid. The error message shown to the user is identical either way, making this failure mode particularly confusing during diagnosis.

Why Different Clients Fail Differently

Not all TLS clients behave the same way when encountering an expired certificate. Understanding the differences explains why "it works in Chrome but not in our backend" is a common debugging scenario.

Browsers: forgiving by design

Modern browsers implement several mitigations that make them more tolerant of server misconfigurations. Chrome and Firefox implement AIA (Authority Information Access) fetching, which means if the server fails to send intermediate certificates, the browser will attempt to download them from the URL specified in the AIA extension of the leaf certificate. Browsers also cache intermediate certificates from previous connections, so a missing intermediate might work in one browser session but fail in another (or fail in a fresh Incognito window).

For expired certificates specifically, browsers show an interstitial warning but allow the user to click through (in most cases). This means some fraction of users will bypass the warning and use the site anyway, giving site operators a false sense that "it's not that bad." In reality, the majority of users (studies suggest 70-90%) will leave immediately without clicking through.

API clients and backend services: strict by default

Libraries like OpenSSL, BoringSSL, and GnuTLS perform strict validation by default and do not implement AIA fetching. When a server sends an incomplete chain or an expired certificate, the TLS handshake fails immediately with a verification error. There is no interstitial, no "click through," no second chance. The connection is simply refused.

This means an expired certificate causes immediate, total failure for all server-to-server communication: API calls, webhook deliveries, payment gateway integrations, mobile app backends, and IoT device connections. These clients represent the "hard failure" surface of an expired certificate, and they are often more business-critical than browser traffic.

Mobile apps: depends on implementation

iOS and Android provide platform-level TLS validation that is generally strict. However, some apps disable certificate validation during development (a practice that occasionally ships to production by accident). Apps that implement certificate pinning will fail even for valid certificate rotations if the pin is not updated. The failure behavior varies per app, making expired certificate impact unpredictable across a mobile user base.

The ACME Protocol: How Automated Renewal Actually Works

Let's Encrypt transformed certificate management by providing free, automated certificates via the ACME (Automatic Certificate Management Environment) protocol, defined in RFC 8555. Understanding how ACME works at the protocol level reveals where automation can silently fail.

The ACME renewal flow

  1. Account registration: The ACME client (certbot, acme.sh, Caddy, etc.) registers an account with the CA by generating an RSA or ECDSA key pair and sending the public key. This happens once and the key is stored locally.
  2. Order creation: The client requests a certificate for one or more domain names. The CA responds with a set of authorization challenges.
  3. Challenge completion: The client must prove control of each domain. The two most common challenge types are:
    • HTTP-01: The client places a token file at http://yourdomain.com/.well-known/acme-challenge/{token}. The CA makes an HTTP GET request to verify the token exists. This requires port 80 to be open and routable to the server running the ACME client.
    • DNS-01: The client creates a TXT record at _acme-challenge.yourdomain.com containing a token value. The CA queries DNS to verify the record exists. This requires the client to have API access to the DNS provider.
  4. Validation: The CA performs the challenge verification from multiple vantage points (Let's Encrypt uses a multi-perspective validation approach since 2020 to mitigate BGP hijack attacks on domain validation).
  5. Certificate issuance: Upon successful validation, the CA issues the certificate. The client downloads the certificate chain and installs it on the web server.
  6. Server reload: The web server must be reloaded or restarted to pick up the new certificate. Some servers (Caddy, Traefik) handle this automatically. Others (Nginx, Apache) require explicit reloading.

Where ACME renewal silently fails

Each step in the ACME flow has specific failure modes that can prevent renewal without generating visible errors.

  • Port 80 blocked: HTTP-01 challenges require the CA to reach port 80 on your server. If a firewall rule, security group, or CDN configuration blocks port 80, the challenge fails. This is the single most common cause of Let's Encrypt renewal failure.
  • DNS API credentials expired: DNS-01 challenges require API access to your DNS provider. If the API token expires, the DNS record cannot be created, and the challenge fails silently.
  • Rate limits: Let's Encrypt enforces rate limits: 50 certificates per registered domain per week, 5 failed validations per account per hostname per hour, and others. If your renewal script is misconfigured and burns through rate limits during failed attempts, subsequent legitimate attempts are rejected.
  • Filesystem permission changes: Certbot stores account keys, certificate files, and renewal configuration in /etc/letsencrypt/. If filesystem permissions change (a common side effect of system updates or container rebuilds), certbot cannot read its own configuration.
  • Cron job not running: Most certbot installations rely on a cron job or systemd timer to trigger renewal checks. If the cron daemon stops, the timer is disabled during a system update, or the renewal hook script has a syntax error, renewals silently stop.
  • Web server reload fails: The certificate is renewed on disk, but the web server is not reloaded. The old (now expired) certificate continues to be served from memory. This is particularly insidious because checking the certificate file on disk shows a valid, recently renewed certificate, while the live server still serves the expired one.
  • CDN caches the old certificate: If your TLS termination happens at a CDN edge (Cloudflare, AWS CloudFront, Fastly), the CDN may cache the old certificate for hours or days after the origin renews. The origin has the new certificate, but users connecting through the CDN still see the old one.
  • Wildcard certificate DNS propagation: Wildcard certificates require DNS-01 challenges. If your DNS provider has eventual consistency (many cloud DNS providers do), the TXT record may not be visible from the CA's vantage point when the challenge is attempted, causing a spurious failure.

Quickly Check Your SSL Expiration

Not sure when your SSL certificate expires? Use our SSL Expiry Countdown to instantly see how many days are left before expiration. Simply enter your domain (optionally with a port for non-HTTPS services) and get an immediate answer - no account or setup required.

Certificate Chain Validation: The Part Everyone Gets Wrong

A TLS certificate is not a standalone document. It is part of a chain of trust that extends from the leaf certificate through one or more intermediate certificates to a root certificate embedded in the client's trust store. Getting the chain right is where most operational errors occur.

How chain building works

When the server sends its certificate during the TLS handshake, it should include the leaf certificate and all intermediate certificates. The root certificate is not included because the client already has it in its trust store. The client builds the chain by matching the Issuer field of each certificate with the Subject field of the next certificate in the chain.

For example, a typical Let's Encrypt chain looks like:

  1. Leaf: CN=yourdomain.com, Issuer=R11
  2. Intermediate: CN=R11, Issuer=ISRG Root X1
  3. Root: CN=ISRG Root X1 (in client trust store, not sent by server)

If the server sends only the leaf certificate without the R11 intermediate, browsers may still work (they can fetch the intermediate via AIA or use a cached copy), but strict TLS clients will fail immediately. This is why testing certificate deployment with a browser gives false confidence.

Cross-signed certificates and chain ambiguity

Certificate chains can be ambiguous. The same leaf certificate may have multiple valid chains if the intermediate CA is cross-signed by multiple root CAs. Let's Encrypt's history provides a textbook example: their R3 intermediate was cross-signed by both ISRG Root X1 (their own root) and DST Root CA X3 (an older IdenTrust root). When DST Root CA X3 expired on September 30, 2021, devices that only trusted the old root and did not have ISRG Root X1 in their trust store started failing to validate Let's Encrypt certificates, even though the certificates themselves were not expired.

This type of failure is particularly hard to diagnose because it affects only older devices (Android 7.0 and below, very old Windows versions, certain embedded systems) while modern devices work fine. External monitoring that checks the full chain from a strict validation perspective catches these cross-signing transition failures.

What to validate beyond expiry dates

A thorough certificate check goes beyond verifying that notAfter is in the future. The complete validation list includes:

  • Leaf certificate expiry date and time
  • Intermediate certificate expiry dates (each one independently)
  • Complete chain sent by server (no missing intermediates)
  • SAN field contains the expected domain(s)
  • Key size meets minimum requirements (2048-bit RSA or 256-bit ECDSA)
  • Signature algorithm is not deprecated (no SHA-1)
  • OCSP stapling is configured and returning valid responses
  • Certificate Transparency SCTs are present (required by Chrome)

How UptyBots Monitors Certificates at the Protocol Level

UptyBots performs certificate validation the way a strict TLS client does, not the way a forgiving browser does. This is a deliberate design choice that catches problems before they affect your API clients, mobile apps, and backend integrations.

  • Full TLS handshake from the public internet. UptyBots initiates a real TLS connection to your server, completing the handshake and reading the certificate chain exactly as an external client would. No shortcuts, no cached intermediates, no AIA fetching.
  • Chain completeness validation. The monitor verifies that the server sends all required intermediate certificates. If an intermediate is missing, you are alerted before strict clients start failing.
  • Multi-threshold expiry alerts. Receive alerts at 30, 14, 7, and 1 day before expiry. Even if you miss the early warnings, the later ones catch your attention before users are affected.
  • Custom port support. Monitor certificates on any port: 443 (HTTPS), 993 (IMAPS), 995 (POP3S), 465/587 (SMTPS), 8443 (admin panels), or any custom port your services use. Each port can serve a different certificate and needs independent monitoring.
  • Historical tracking. Every certificate check is logged with the full chain details. When a certificate rotates, you can see exactly when the new certificate appeared and verify it was deployed correctly.
  • Multiple notification channels. Email, Telegram, webhook. Choose the channels that reach the right people on your team. For certificates protecting revenue-critical services, use at least two independent channels.

Building a Certificate Monitoring Strategy by Service Type

Different services have different certificate management patterns and failure modes. Here is a practical breakdown by service type.

Web servers (Nginx, Apache, Caddy)

The most common case. Monitor the primary domain and every subdomain that serves HTTPS traffic. Pay special attention to subdomains that use separate certificates from the main domain (staging.example.com, admin.example.com, api.example.com). Even if the main domain uses a wildcard certificate, subdomains on separate servers or CDN configurations may have their own certificates with independent expiry dates.

Mail servers (Postfix, Dovecot, Exchange)

Mail server certificates are often forgotten because they are not visible in a browser. Monitor port 993 (IMAPS), 995 (POP3S), and 465 or 587 (SMTPS). When a mail server certificate expires, email clients display confusing security warnings that cause users to think email is "hacked." Corporate environments with strict TLS policies will stop receiving mail entirely.

API endpoints and microservices

Internal APIs that communicate over HTTPS need their own certificate monitors, especially if they use certificates from a different CA or with a different renewal schedule than the public-facing site. A common pattern is the main site using Cloudflare's edge certificate while the API server behind it uses a Let's Encrypt certificate with independent renewal.

Load balancers and reverse proxies

TLS termination often happens at the load balancer (AWS ALB, HAProxy, Nginx reverse proxy). The certificate on the load balancer is what clients see, even if the backend servers have their own certificates. Monitor the load balancer's certificate, not the backend. If you change load balancers (migration from HAProxy to AWS ALB, for example), verify that the new certificate monitoring target reflects the new termination point.

CDN edge certificates

CDNs like Cloudflare, CloudFront, and Fastly manage edge certificates on your behalf, but management is not infallible. Monitor the certificate as seen from the public internet (the edge certificate), not the origin certificate. CDN edge certificate renewals can lag or fail, and the CDN's own monitoring may not alert you at the threshold you need.

ACME Failure Recovery: What to Do When Automation Breaks

When your ACME renewal fails and you discover it through monitoring (rather than through user complaints, which is the goal), here is a systematic diagnosis approach based on the most common failure modes.

  1. Check the renewal log. Certbot logs to /var/log/letsencrypt/letsencrypt.log. Acme.sh logs to ~/.acme.sh/acme.sh.log. The log will show the specific challenge that failed and the error returned by the CA.
  2. Verify port 80 reachability. From an external network, attempt curl -v http://yourdomain.com/.well-known/acme-challenge/test. If the connection times out, a firewall or CDN is blocking port 80. Let's Encrypt requires port 80 for HTTP-01 challenges even if your site only uses port 443.
  3. Check DNS propagation for DNS-01 challenges. Query the TXT record from multiple resolvers: dig @8.8.8.8 _acme-challenge.yourdomain.com TXT. If the record is missing or has not propagated, the DNS API call may have failed or the propagation delay exceeded the ACME timeout.
  4. Verify rate limits. Check https://crt.sh for recent certificate issuances for your domain. If you see many certificates issued in the past week, you may be hitting Let's Encrypt's rate limits. Wait for the rate limit window to reset (1 week for most limits).
  5. Confirm the web server reloaded. Run openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -dates to check the currently served certificate. Compare the notAfter with the certificate file on disk. If they differ, the web server needs to be reloaded.
  6. Test from the client's perspective. Do not test from the server itself. Test from an external location, through the same network path your users take. CDNs, load balancers, and WAFs can all serve cached or different certificates than what the origin has.

Frequently Asked Questions

How long are SSL certificates valid?

Public SSL certificates issued by trusted CAs have a maximum validity of 397 days (roughly 13 months). Browsers reject certificates with longer validity. Free Let's Encrypt certificates are valid for 90 days, encouraging automation. Internal CAs can issue longer-validity certificates, but those are not trusted by public browsers.

What if my auto-renewal works most of the time?

"Most of the time" is exactly when you need monitoring. Auto-renewal that works 99% of the time still fails 1% of the time, and that 1% is when your certificate expires. External monitoring catches the rare failures that internal automation misses.

Can I monitor certificates on internal-only servers?

External monitoring can only check certificates that are reachable from the public internet. For internal certificates, use an internal monitoring tool that runs inside your network. UptyBots handles the public-facing certificates, which are usually the most critical.

How early should I get the first alert?

30 days before expiration is a good first alert for manually renewed certificates. For Let's Encrypt (90-day validity, renewal at 30 days remaining), an alert at 20 days remaining indicates that automated renewal has failed and manual intervention is needed. Add additional alerts at 14, 7, and 1 day for progressively urgent reminders.

Does certificate monitoring check the full chain or just the leaf?

UptyBots validates the complete chain from leaf through intermediates. This catches missing intermediate certificates, expired intermediates, and cross-signing transition issues that leaf-only checks miss.

What does UptyBots cost for SSL monitoring?

UptyBots offers a free tier that covers basic SSL monitoring for small projects. Paid plans add more monitors, faster checks, longer history, and additional notification channels. The cost is trivial compared to the cost of a single certificate expiration incident.

Conclusion

An expired SSL certificate is not just a visual annoyance. At the protocol level, it triggers a fatal TLS alert that terminates the connection before a single byte of application data is exchanged. Every browser shows a scary warning. Every API client refuses to connect. Every webhook delivery fails. The damage is instant and total.

Automated renewal via ACME has dramatically reduced the frequency of expiry incidents, but it has also created a false sense of security. The ACME flow has at least eight distinct failure points, from blocked ports to stale DNS credentials to web server reload failures, any one of which can cause renewal to fail silently while the existing certificate counts down to zero.

External certificate monitoring is the safety net that catches what automation misses. By performing a real TLS handshake from the public internet and validating the full certificate chain with strict client behavior, monitoring detects expiring certificates, missing intermediates, and deployment failures weeks before they affect users. The setup takes minutes. The alternative is discovering the problem from a flood of support tickets and a dashboard full of errors.

See setup tutorials or get started with UptyBots SSL monitoring today.

Ready to get started?

Start Free