Skip to content
ecdsa.com
← All articles

47-day TLS certificates: the schedule and what to automate

The first cut came in March 2026. By 2029 public certificates last 47 days and a domain validation is good for 10. The exact schedule from the Baseline Requirements, and tested ACME, ARI and monitoring setups that keep up with it.

Short answer. CA/Browser Forum ballot SC-081, adopted on 11 April 2025, cuts the maximum validity of publicly trusted TLS certificates in three steps. Certificates issued from 15 March 2026 may last up to 200 days, from 15 March 2027 up to 100 days, and from 15 March 2029 up to 47 days. The time a CA may reuse a domain validation shrinks on the same dates: 200 days, then 100, then 10. In practice every certificate has to be issued and deployed by automation (ACME). Renewal should follow the CA's ARI window, and you need monitoring that alerts you while there is still time to fix a broken renewal. Private CAs are not affected.

The schedule

The rules live in sections 6.3.2 and 4.2.1 of the Baseline Requirements (version 2.3.1, October 2026). Ballot SC-081v3 was proposed by Apple and endorsed by Sectigo, Google Chrome and Mozilla. It passed with 25 CA votes in favour, none against and 5 abstentions, and all four browser vendors voted yes.

Certificate issuedMaximum validityDomain/IP validation reuseOrganization identity reuse
before 15 March 2026398 days398 days825 days
15 March 2026 to 14 March 2027200 days200 days398 days
15 March 2027 to 14 March 2029100 days100 days398 days
from 15 March 202947 days10 days398 days

Some details that matter when you plan around these numbers:

  • The limits are upper bounds that CAs enforce at issuance. A certificate issued on 14 March 2026 could still be valid for 398 days. Nothing forces you to replace it before it expires, but its replacement will be short.
  • "Validity" counts both ends. The BR defines it as the period from notBefore through notAfter inclusive, and it recommends one day of headroom: certificates "SHOULD NOT" exceed 199, 99 and 46 days.
  • The validation reuse limit is the bigger change. Today a CA can reuse proof that you control example.com for months. From 2029 the proof must be at most 10 days old, so almost every issuance needs a fresh domain validation, and the DNS or HTTP challenge has to be automated too.
  • Organization details in OV and EV certificates (company name, address) may be reused for 398 days instead of 825.
  • Scope. The BR governs TLS server certificates from publicly trusted CAs. Certificates from your own internal CA, client certificates and S/MIME certificates fall under other rules or none.

What CAs issue today

On 20 October 2026, the certificates served by a few large sites looked like this. The output comes from the lifetimes.sh script in the monitoring section:

lifetimes.sh, 20 October 2026 (OpenSSL 3.5.7)
letsencrypt.org        Let's Encrypt              2026-09-04  ->  2026-12-03  (90 days)
www.google.com         Google Trust Services      2026-09-28  ->  2026-12-21  (84 days)
github.com             Sectigo Limited            2026-09-01  ->  2026-11-29  (90 days)
www.microsoft.com      Microsoft Corporation      2026-01-22  ->  2027-01-17  (360 days)
www.amazon.com         Amazon                     2026-01-19  ->  2027-01-11  (358 days)
www.digicert.com       DigiCert Inc               2026-10-11  ->  2026-11-26  (47 days)

Two of them still carry certificates of almost a year, issued in January 2026, just before the 200-day limit took effect. DigiCert already serves a 47-day certificate on its own site. Let's Encrypt's published plan moves faster than the BR requires:

  • 13 May 2026: the opt-in tlsserver profile issues 45-day certificates.
  • 10 February 2027: the default classic profile issues 64-day certificates with a 10-day authorization reuse period.
  • 16 February 2028: classic issues 45-day certificates with a 7-hour authorization reuse period.

The live ACME directory lists the profiles you can request today:

GET https://acme-v02.api.letsencrypt.org/directory (abridged, 20 October 2026)
"meta": {
  "profiles": {
    "classic": "https://letsencrypt.org/docs/profiles#classic",
    "shortlived": "https://letsencrypt.org/docs/profiles#shortlived",
    "tlsserver": "https://letsencrypt.org/docs/profiles#tlsserver"
  }
},
"renewalInfo": "https://acme-v02.api.letsencrypt.org/acme/renewal-info"

What to automate

With 398-day certificates, a manual yearly renewal was annoying but survivable. With 47-day certificates and 10-day validation reuse, manual renewal is an error-prone task at least eight times a year for every name, and closer to twelve if you renew at two thirds of the lifetime. The work splits into four parts.

1. Issuance through ACME. Use an ACME client (RFC 8555) for every certificate from a public CA. Most commercial CAs offer ACME endpoints too, often with external account binding. If a certificate still arrives by email, a portal download or a ticket, put it on the list first.

2. Validation that runs unattended. Choose a challenge that works without a person:

  • http-01 needs port 80 reachable on every host that serves the name.
  • dns-01 needs API access to your DNS provider. Scope the token to _acme-challenge records where the provider allows it.
  • tls-alpn-01 runs entirely on port 443.

Two newer methods are written for exactly this situation. "DNS Labeled with Account ID", the ACME dns-account-01 challenge in BR §3.2.2.4.21, lets several ACME accounts validate the same name without fighting over one _acme-challenge record. "DNS TXT Record with Persistent Value" (§3.2.2.4.22, ballot SC-088) lets you publish a standing record once:

Persistent DCV record, the example from BR §3.2.2.4.22
_validation-persist.example.com IN TXT "authority.example; accounturi=https://authority.example/acct/123; persistUntil=1782424856"

The CA may treat each check of that record as good for at most 10 days. It re-checks the record itself, though, so nobody has to touch DNS for each renewal. Ask your CA whether it supports the method before you rely on it.

3. Renewal that follows the CA. Renew early and let the CA steer the timing:

  • Renew at about two thirds of the lifetime. That is day 30 of a 45-day certificate. Let's Encrypt states that "renewing at a hardcoded interval of 60 days will no longer be sufficient." Since version 4.0, certbot renews with a third of the lifetime left instead of at a fixed 30 days.
  • Use ARI (RFC 9773), covered in the next section. The CA tells each client when to renew, and it can pull that window forward when it has to revoke certificates in bulk.
  • Request the profile explicitly if you want 45-day certificates before your CA's default changes.

4. Deployment to every copy. Renewing the file on disk is not the end. List every place a certificate is copied to:

  • load balancers and CDNs that take uploaded certificates,
  • Kubernetes secrets,
  • Java keystores and PKCS#12 bundles,
  • appliances, mail servers, databases and message brokers,
  • mobile apps that pin a leaf certificate.

Each copy needs either a reload hook or an integration that fetches the new certificate. Pinning a leaf certificate or its key in an app becomes unworkable at this cadence. Pin a CA key instead, or better, don't pin.

This test runs certbot 5.8.0 against a local Pebble 2.10.1 ACME server whose tlsserver profile issues 45-day certificates. It shows that the profile request and the renewal configuration work as documented:

certbot 5.8.0 against Pebble 2.10.1 (abridged)
$ certbot certonly --standalone --non-interactive --agree-tos --register-unsafely-without-email \
    --server https://localhost:14000/dir -d app.example.test --preferred-profile tlsserver
Account registered.
Requesting a certificate for app.example.test
Successfully received certificate.
This certificate expires on 2026-12-04.
$ openssl x509 -in /etc/letsencrypt/live/app.example.test/cert.pem -noout -startdate -enddate
notBefore=Oct 20 11:47:52 2026 GMT
notAfter=Dec  4 11:47:51 2026 GMT
$ grep -E "preferred_profile|server" /etc/letsencrypt/renewal/app.example.test.conf
preferred_profile = tlsserver
server = https://localhost:14000/dir
$ certbot renew --non-interactive
Processing /etc/letsencrypt/renewal/app.example.test.conf
Certificate not yet due for renewal

certbot stores the profile in the renewal configuration, so every later renewal asks for it again. The --preferred-profile flag exists since certbot 4.0. If the CA's directory does not list the named profile, it falls back to the CA's default. --required-profile makes issuance or renewal fail instead. Profiles come from draft-ietf-acme-profiles, which was waiting for IESG review in October 2026. Clients other than certbot have their own flag names.

ACME Renewal Information (ARI)

ARI (RFC 9773, June 2025) turns renewal timing from a client-side guess into a question to the CA. For each certificate, the client builds an identifier from the certificate's Authority Key Identifier and serial number:

RFC 9773 §4.1
url = renewalInfo || '/' || base64url(AKI keyIdentifier) || '.' || base64url(Serial)

It then polls that URL without authentication. The response holds a suggestedWindow, and a Retry-After header says when to ask again. You can query it yourself for any Let's Encrypt certificate:

ari.sh: ask Let's Encrypt when a certificate should be renewed
#!/bin/bash
set -e
host="$1"
openssl s_client -connect "$host:443" -servername "$host" </dev/null 2>/dev/null | openssl x509 -out cert.pem
aki=$(openssl x509 -in cert.pem -noout -ext authorityKeyIdentifier | grep -o -E '([0-9A-F]{2}:){19}[0-9A-F]{2}' | tr -d ':')
serial=$(openssl x509 -in cert.pem -noout -serial | cut -d= -f2)
# The DER INTEGER content keeps a leading 00 byte when the high bit is set.
[ $(( 16#${serial:0:1} )) -ge 8 ] && serial="00$serial"
b64url() { python3 -c 'import sys,base64; print(base64.urlsafe_b64encode(bytes.fromhex(sys.stdin.read().strip())).decode().rstrip("="))'; }
id="$(printf %s "$aki" | b64url).$(printf %s "$serial" | b64url)"
ari=$(curl -s https://acme-v02.api.letsencrypt.org/directory | grep -o '"renewalInfo": *"[^"]*"' | cut -d'"' -f4)
openssl x509 -in cert.pem -noout -issuer -startdate -enddate
echo "GET $ari/$id"
curl -s -D - "$ari/$id" | grep -i -E '^retry-after|^\{|"'
bash ari.sh letsencrypt.org (20 October 2026, abridged)
issuer=C=US, O=Let's Encrypt, CN=YE2
notBefore=Sep  4 14:34:32 2026 GMT
notAfter=Dec  3 14:34:31 2026 GMT
GET https://acme-v02.api.letsencrypt.org/acme/renewal-info/uVnyjs8i8IbTN0j_dhQYuoLYVYc.BUOTO-OGs6KzrdU08hA7yLZf
retry-after: 25769
{
  "suggestedWindow": {
    "start": "2026-11-02T17:18:36Z",
    "end": "2026-11-04T12:29:25Z"

The window opens 59 days into this 90-day certificate, at about two thirds of its lifetime. The client should pick a random moment inside the window, which spreads renewals over time. If the CA has to revoke certificates in bulk, it moves the window into the past, and well-behaved clients renew within hours instead of failing at expiry. When renewing, the client sends the old certificate's identifier in the replaces field of its new order.

ARI support in common clients, from their release notes:

ClientARI sinceNotes
certbot4.1.0 (June 2025)On by default in certbot renew. 5.0 stores Retry-After across runs
Caddy2.8.0 (May 2024)Built in through CertMagic
lego4.12.0 (May 2023)First implementation. The identifier format was updated as the draft changed
acme.sh3.1.4 (July 2026)On by default. NO_ARI=1 disables it. The cron job now runs every 6 hours
cert-manager1.21.0 (July 2026)Experimental, behind the ACMEUseARI feature gate

Monitoring that catches a broken renewal

Automation fails quietly: an expired DNS API token, a firewall change that blocks port 80, a reload hook that stopped working. With a 47-day certificate renewed at day 30, you have about 17 days between the first failed renewal and an outage. Alert early in that gap.

From outside. Probe every public name, not only the ones you remember. The Prometheus blackbox exporter exposes the expiry of the served chain as probe_ssl_earliest_cert_expiry:

blackbox exporter 0.25.0: /probe?module=https&target=https://www.digicert.com (20 October 2026)
probe_ssl_earliest_cert_expiry 1.795737599e+09
probe_success 1
probe_tls_version_info{version="TLS 1.3"} 1

These two alert rules pass promtool check rules (Prometheus 3.5.0). The first fires when the renewal is overdue, the second when an outage is close:

cert-rules.yml
groups:
  - name: certificates
    rules:
      - alert: CertificateRenewalOverdue
        # Fires when less than a third of a 47-day lifetime (about 16 days) is left:
        # the renewal job should have replaced the certificate by now.
        expr: probe_ssl_earliest_cert_expiry - time() < 16 * 86400
        for: 1h
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }}: certificate expires in {{ $value | humanizeDuration }}"
      - alert: CertificateExpiresSoon
        expr: probe_ssl_earliest_cert_expiry - time() < 7 * 86400
        for: 10m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.instance }}: certificate expires in {{ $value | humanizeDuration }}"

From a script. openssl x509 -checkend N exits with status 1 if the certificate expires within N seconds, which is enough for a cron job or a CI step:

openssl x509 -checkend, www.digicert.com (20 October 2026)
$ openssl x509 -in cert.pem -noout -enddate
notAfter=Nov 26 23:59:59 2026 GMT
$ openssl x509 -in cert.pem -noout -checkend $((30 * 86400)); echo "exit status: $?"
Certificate will not expire
exit status: 0
$ openssl x509 -in cert.pem -noout -checkend $((45 * 86400)); echo "exit status: $?"
Certificate will expire
exit status: 1

The survey table at the top of this page came from this script:

lifetimes.sh: validity period of the certificate each host serves
#!/bin/bash
for host in "$@"; do
  openssl s_client -connect "$host:443" -servername "$host" </dev/null 2>/dev/null | openssl x509 -out /tmp/c.pem 2>/dev/null || { echo "$host: no certificate"; continue; }
  nb=$(openssl x509 -in /tmp/c.pem -noout -startdate | cut -d= -f2)
  na=$(openssl x509 -in /tmp/c.pem -noout -enddate | cut -d= -f2)
  issuer=$(openssl x509 -in /tmp/c.pem -noout -issuer -nameopt multiline | grep -E "organizationName" | head -1 | cut -d= -f2 | sed 's/^ *//')
  days=$(( ($(date -d "$na" +%s) - $(date -d "$nb" +%s) + 1) / 86400 ))
  printf '%-22s %-26s %s  ->  %s  (%s days)\n' "$host" "$issuer" "$(date -u -d "$nb" +%F)" "$(date -u -d "$na" +%F)" "$days"
done

From the CA's side. Certificate Transparency logs record every certificate issued for your domains. A CT monitor shows renewals that happened and certificates you didn't expect. See Certificate Transparency for developers, or look up a domain's history with the CT history tool. To see how ready a set of domains is, the certificate lifetime calculator works through the schedule for each certificate you have.

CAA and account binding

Shorter validation reuse means more validations, and each one checks your CAA records. From 15 March 2027 (ballot SC-098), CAs must also honour the accounturi and validationmethods parameters from RFC 8657. That lets you limit issuance to your own ACME account and your chosen challenge type:

CAA limited to one ACME account and the dns-01 challenge
example.com. IN CAA 0 issue "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/123456789; validationmethods=dns-01"

The CAA record generator builds these records. Keep in mind that a stale CAA record will block your own renewals, which now happen at least eight times a year instead of once.

Common mistakes

  • A fixed renewal interval. "Renew every 60 days" already fails for 45-day certificates. Renew on a fraction of the lifetime, or on ARI.
  • Renewing without reloading. The new file sits on disk while the server keeps serving the old certificate from memory until it expires. Test the deploy hook, not just the renewal.
  • Forgetting the copies. The origin renews automatically, but the CDN or load balancer still has a manually uploaded certificate.
  • Alerting at 7 days. With 47-day certificates, an alert a week before expiry leaves no time to debug a DNS API or firewall problem. Alert when the renewal is overdue.
  • Pinning leaf keys in mobile apps or API clients. Every renewal with a new key breaks them.
  • Assuming private PKI must follow. Your internal CA can keep its own policy. Short lifetimes are still a good idea there, but they are your choice.

Sources

Command output was produced on 20 October 2026 in node:24.22.0-trixie (OpenSSL 3.5.7, curl 8.14.1), certbot/certbot:v5.8.0 with ghcr.io/letsencrypt/pebble:2.10.1, quay.io/prometheus/blackbox-exporter:v0.25.0 and prom/prometheus:v3.5.0.