Bali, Indonesia
Insights

Why a CAA Record Can Block Let's Encrypt Renewal and How to Check It

October 24, 2026
0:00
Certbot or your control panel's AutoSSL reports a renewal failure that mentions CAA, yet the domain resolves, the challenge file is reachable, and the same certificate was issued without trouble a few months ago. That combination usually means validation is not the problem. Something in DNS is telling certificate authorities who may issue for this name, and Let's Encrypt is either not on that list or cannot read the list at all. This guide stays on the command line. The goal is to see exactly what Let's Encrypt sees, before you change anything and again after.
A CAA (Certification Authority Authorization) record is a DNS record that lists which certificate authorities are allowed to issue certificates for a domain. Public CAs are required by industry rules to check it before issuing. If a CAA record exists and does not name the CA, the CA must refuse, no matter how cleanly you passed the HTTP or DNS challenge. A record has three parts: a flag, a tag, and a value. For example, 0 issue "letsencrypt.org" means Let's Encrypt may issue normal certificates. 0 issuewild "letsencrypt.org" covers wildcard certificates. 0 iodef "mailto:[email protected]" asks CAs to report rejected requests, and has no effect on whether issuance is allowed. Two details explain most renewal surprises. First, having no CAA record at all means any CA may issue. The moment you add one record, everything not listed is blocked. Second, the check happens at issuance time, not only when the domain was first validated. Let's Encrypt can reuse a recent authorization for a domain, but it still rechecks CAA close to issuance. So a CAA record added last week can break a renewal even though nothing else changed. In support, this pattern often follows a customer buying a commercial certificate from another CA, being told to add a CAA record for that CA, and forgetting about it. The commercial certificate keeps working. The Let's Encrypt certificate on a subdomain quietly stops renewing.
CAA lookup climbs the DNS tree. The CA asks for CAA on the exact name in the certificate. If that name has no CAA records, it asks the parent, then the grandparent, and stops at the first name that returns any CAA records. Those records are the ones that count. Records further up are ignored, and the root is never checked. That means shop.example.com with no CAA of its own inherits whatever example.com publishes. It also means a CAA record on shop.example.com fully replaces the parent's policy for that name. It does not add to it. To see what the CA sees, query each level yourself. This loop is read-only and walks from the full name up to the TLD:
BASH
# Replace with the exact name that failed renewal
name='shop.example.com'
while [ -n "$name" ]; do
  echo "== $name"
  dig +short CAA "$name"
  # Strip the leftmost label; stop after the last one
  case "name" in *.*) name="{name#*.}" ;; *) name='' ;; esac
done
The first level that prints records is the relevant set. Everything below it printed nothing, and everything above it does not matter.
TEXT
Illustrative output format:
== shop.example.com
== example.com
0 issue "sectigo.com"
0 iodef "mailto:[email protected]"
== com
Here shop.example.com has no CAA, so example.com decides. Only one CA is named, Let's Encrypt is not among them, and renewal for shop.example.com will be refused. The fix is to add 0 issue "letsencrypt.org" alongside the existing record at example.com, or to publish a separate CAA set on shop.example.com if you want that subdomain to have its own policy. Removing the existing record also works, but it lifts the restriction for every CA, so check with whoever added it first. If your dig is very old and complains that CAA is an unknown type, dig TYPE257 example.com asks for the same thing by its numeric type.
CNAMEs are where people misread the result. CAA lookup uses normal DNS resolution, so when a name is a CNAME, the resolver follows the alias and returns the CAA records at the target. Under the current standard (RFC 8659), if the target has no CAA records, the climb continues with the parent of your original name, not the parent of the alias target. In practice, say www.example.com is a CNAME to sites.hostingplatform.net. If sites.hostingplatform.net publishes CAA records, those apply to your www certificate, even though you do not control that zone. If it publishes none, the CA moves on to example.com. You can spot this in the loop output. With +short, dig prints the CNAME target on its own line before any CAA records, so a line ending in a dot is the alias, and the records below it belong to the target. To see it more explicitly:
BASH
# Is the name an alias, and what CAA does the target publish?
dig +short CNAME www.example.com
dig +short CAA sites.hostingplatform.net

# Ask the authoritative servers directly, bypassing caches
dig +short NS example.com
dig @ns1.example.net CAA example.com +norecurse

# A clean lookup shows status: NOERROR; SERVFAIL is a problem on its own
dig CAA shop.example.com | grep -i 'status:'
If the target zone blocks Let's Encrypt and you cannot change it, your options are to ask the platform owner, or to stop using a CNAME for that name if the setup allows it. You cannot override a CNAME target's CAA by adding CAA on the alias name, because a name that has a CNAME cannot hold other records.
Sometimes Let's Encrypt is listed and renewal still fails. The value field can carry parameters that narrow the permission, and these tend to bite at renewal time because something about the renewal differs from the original issuance. validationmethods limits which challenge types are allowed. A record like 0 issue "letsencrypt.org; validationmethods=dns-01" blocks any renewal that uses the HTTP challenge. This shows up after a site moves to a new server where the client defaults to HTTP validation, or when a control panel handles renewal differently from the tool that issued the first certificate. accounturi pins issuance to one ACME account. ACME is the protocol Let's Encrypt clients use, and each client registers an account. If the server is rebuilt, certbot is reinstalled, or renewal moves from certbot to a panel's built-in tool, a new account is created and the CAA record rejects it. Compare the account URI in the record with the one your current client uses. Where certbot stores it depends on your setup, but it lives under the client's account directory, not in the certificate. issuewild matters for wildcard certificates. If an issuewild record exists at the relevant level, it takes precedence over issue for wildcard names. So 0 issue "letsencrypt.org" plus 0 issuewild "anotherca.example" allows a normal certificate from Let's Encrypt but blocks *.example.com. The reverse also happens: a plain name fails while the wildcard works. Finally, look at the flag. A flag of 128 marks the record as critical. If a CA sees a critical tag it does not understand, it must refuse. A typo in the tag name combined with flag 128 blocks everyone. Most records should use flag 0.
A CAA error does not always mean a record says no. If the CA cannot get a clean answer, it refuses rather than guess. The message typically mentions SERVFAIL or a timeout while looking up CAA, something like DNS problem: SERVFAIL looking up CAA for example.com (illustrative wording). Common causes are authoritative DNS software that mishandles record types it does not recognize, broken DNSSEC signatures on the zone, or one nameserver in the NS set that is out of sync or unreachable. The fact that A records resolve proves little, because many resolvers have those cached and the CA queries CAA fresh. The status line check in the earlier block is the quickest test. Run the direct authoritative query against every nameserver listed by dig NS, not just the first one. An empty answer with NOERROR is fine; it means no record at that level. SERVFAIL, REFUSED, or a timeout on any server needs fixing at the DNS provider before renewal will succeed. If DNSSEC is enabled, dig +dnssec CAA example.com against a validating public resolver helps show whether validation is the failure point.
Once you edit the record, run the same loop again and confirm the relevant level now includes letsencrypt.org, with no parameters that conflict with how your client actually renews. Check each authoritative nameserver directly, because public resolvers may keep the old answer until the record's TTL expires. Then retry the renewal. For certbot, certbot renew --dry-run tests against the staging environment without replacing your live certificate, and staging performs CAA checks too. The habit worth building is simple: when a renewal error mentions CAA, stop looking at the web server and the challenge files. Walk the name up the tree with dig, follow any CNAME, read the parameters, and confirm every nameserver answers cleanly. Those four checks usually point straight at the cause.