What a CAA record does
A CAA (Certification Authority Authorization) record is a DNS record, type 257, that lists which certificate authorities may issue certificates for a name. Since September 2017, every publicly trusted CA has had to look it up before issuing and refuse if it isn’t on the list.
That’s the whole mechanism, and its limits matter as much as what it does:
- It is checked by the CA at issuance time. Browsers don’t read CAA. A certificate that already exists keeps working no matter what you put in DNS.
- It only binds CAs that follow the public rules. It does nothing against a compromised CA, or a private CA you installed on your own devices.
- With no CAA record, any public CA may issue for your domain if the requester passes validation. That’s the default for most domains, and it isn’t broken. CAA narrows the list; it doesn’t add validation.
So CAA is a cheap guard against one specific failure: someone gets a certificate for your name from a CA you never use, through a weaker validation path or a mistake. It’s worth having. It’s also the reason a renewal can suddenly fail with CAA record for example.com prevents issuance, which is what most people searching for this are dealing with.
If you’re a visitor, CAA never produces a browser error. If a site shows a certificate warning, the cause is elsewhere: expiry, a name mismatch, or an untrusted chain.
Record syntax
Each CAA record has three parts: a flags byte, a tag, and a quoted value. In zone-file form:
example.com. 3600 IN CAA 0 issue "letsencrypt.org"
example.com. 3600 IN CAA 0 issuewild ";"
example.com. 3600 IN CAA 0 iodef "mailto:security@example.com"
In a DNS provider’s web form you usually enter the same three fields separately: flags 0, tag issue, value letsencrypt.org.
The tags defined in RFC 8659:
| Tag | Meaning |
|---|---|
issue | This CA may issue certificates for this name. One record per CA; several records mean any of them may issue. |
issuewild | Same, but for wildcard certificates only. If any issuewild record exists, it replaces issue for wildcard requests. If none exist, wildcards follow issue. |
iodef | Where a CA may report a request it refused (mailto: or https: URL). CAs aren’t required to send these reports, and many don’t. Treat it as optional. |
The value ";" (a CA identifier left empty) means “no CA”. 0 issue ";" forbids all issuance for the name, which is a sensible setting for a domain that should never have a certificate, such as a parked domain or a mail-only domain.
The flags byte is almost always 0. The only defined flag is 128, “issuer critical”: it tells a CA that if it doesn’t understand this record’s tag, it must not issue. You’d only use it with a tag you need every CA to honour, and setting it on an unknown tag blocks issuance everywhere. Leave it at 0 unless you know why you need 128.
A separate issuemail tag exists for S/MIME (email signing) certificates. It doesn’t affect TLS certificates for websites.
CA identifiers
The value in issue is a domain name the CA publishes as its CAA identifier. Use the one your CA documents. The common ones:
| CA | Identifier |
|---|---|
| Let’s Encrypt | letsencrypt.org |
| Google Trust Services | pki.goog |
| AWS Certificate Manager | amazon.com (AWS also accepts amazontrust.com and a few related values) |
| DigiCert | digicert.com |
| Sectigo | sectigo.com |
Don’t guess the identifier from the name on the certificate. Resellers, hosting companies and CDNs often issue through a CA you didn’t pick. Look at who actually issued your current certificate with the SSL check or:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -issuer
Then do the same for every hostname that has its own certificate, including the ones a third party manages for you: the CDN, the help desk or status page on a CNAME, the mail host. Every one of those issuers needs an issue entry, or their next renewal fails. Searching Certificate Transparency logs for your domain is the most complete way to see every CA that has issued for your names in the past year.
Copy-paste examples
Let’s Encrypt only, wildcards included:
example.com. CAA 0 issue "letsencrypt.org"
Let’s Encrypt and Google Trust Services, but no wildcards from anyone:
example.com. CAA 0 issue "letsencrypt.org"
example.com. CAA 0 issue "pki.goog"
example.com. CAA 0 issuewild ";"
Normal certificates from Let’s Encrypt, wildcards only from DigiCert:
example.com. CAA 0 issue "letsencrypt.org"
example.com. CAA 0 issuewild "digicert.com"
Here a wildcard request to Let’s Encrypt fails, because once issuewild exists, issue no longer applies to wildcards.
No certificates at all for a domain you don’t use for the web:
example.org. CAA 0 issue ";"
Pinning issuance to your own ACME account
RFC 8657 adds two parameters to issue: accounturi restricts issuance to one ACME account, and validationmethods restricts how the domain may be validated.
example.com. CAA 0 issue "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234567890; validationmethods=dns-01"
With this record, someone who controls your web server but not your ACME account, or who could pass an HTTP-01 challenge by some other route, still can’t get a certificate from Let’s Encrypt. Let’s Encrypt supports both parameters; check your CA’s documentation before relying on them elsewhere. With certbot, certbot show_account prints the account URL. Remember to update the record if you ever recreate the account, or renewals stop.
How a CA finds the record: climbing the tree
A CA doesn’t only look at the exact name in the request. It looks for the closest CAA record at or above it:
- Query CAA for the requested name, for example
app.eu.example.com. - If there’s no CAA record there, drop the leftmost label and query
eu.example.com. - Then
example.com, and so on up to the top-level domain. - The first name that has any CAA records is the one used. Everything above it is ignored.
Two consequences catch people.
A record on example.com governs every subdomain that has no CAA of its own. Lock the apex to Let’s Encrypt and you’ve also locked shop.example.com, mail.example.com and every other name below it.
Records don’t merge. If example.com allows letsencrypt.org and you add 0 issue "digicert.com" on shop.example.com, then shop.example.com allows only DigiCert. Let’s Encrypt is now refused for that name, because the CA stopped climbing at shop.example.com. A subdomain record must list every CA that subdomain needs.
To see what a CA sees, walk the tree yourself:
name=app.eu.example.com
while [ -n "$name" ]; do
echo "== $name"; dig +short CAA "$name"
case "$name" in *.*) name=${name#*.} ;; *) name="" ;; esac
done
== app.eu.example.com
== eu.example.com
== example.com
0 issue "letsencrypt.org"
0 issuewild ";"
== com
Here example.com is the record in force for app.eu.example.com. The DNS lookup shows CAA records for any single name from outside your network, which is a quick cross-check for each level.
CNAMEs change the answer
If the name in the request is a CNAME, a CAA query for it follows the CNAME, like any DNS lookup. So for
status.example.com. CNAME example.statuspage-provider.net.
the CA gets the CAA records of example.statuspage-provider.net, if that name has any. If the provider publishes CAA there, those records govern your status.example.com, and your own records are never consulted for that name.
If the target has no CAA, the CA climbs your tree, from example.com, not the provider’s. Under RFC 8659 the climb follows the original name. (The older RFC 6844 also climbed the target’s parents. That was dropped.)
In practice:
- A third-party service on a CNAME, a help desk, status page, docs host or storefront, usually issues the certificate for your custom domain itself. If its target has no CAA, your apex record decides whether it can. Lock the apex to one CA and that service’s renewal fails months later, usually without anyone connecting it to the DNS change. Before tightening CAA, list every CNAME to an outside service and find out which CA it uses.
- You can’t add a CAA record to a name that is a CNAME. DNS doesn’t allow other records next to a CNAME. To control CAA for that name, you’d have to replace the CNAME, which usually isn’t possible with a SaaS.
Fixing “CAA record prevents issuance”
Let’s Encrypt reports this as an error of type urn:ietf:params:acme:error:caa with text like CAA record for example.com prevents issuance. Other CAs word it differently, but the steps are the same.
Note the name in the message. It is often a parent of the name you requested, which tells you where the climb stopped.
- Walk the tree with the loop above, starting from the exact name in the order, wildcard prefix removed. The first level with records is the one in force.
- Check for a CNAME on that name. If there is one, the target’s CAA may be what you’re reading.
- Compare the identifier with the CA you’re actually requesting from. Some ACME clients support several CAs and their default has changed between versions, and hosting panels sometimes switch CAs without telling you. Check which CA your client is actually talking to (the ACME directory URL in its config or logs) before editing DNS.
- Wildcard requests: if any
issuewildrecord exists at that level, it alone decides.issuewild ";"left over from an old lockdown is a classic cause. accounturiorvalidationmethods: if the record has these parameters, the request must come from that account and use that method. A new server with a fresh ACME account fails here.- Fix the record, then wait. Resolvers keep the old answer for the TTL. The CA rules also let a CA rely on a CAA check for the record’s TTL or 8 hours, whichever is longer, so a retry five minutes later may still see the old record. Lower the TTL a day before planned CAA changes.
A different failure looks similar: the CAA lookup itself fails. If your authoritative nameservers time out or return SERVFAIL for CAA queries, which some old DNS appliances and load balancers did for record types they don’t understand, the CA usually can’t treat that as “no record” and refuses to issue. Let’s Encrypt reports this as a DNS error during the CAA check rather than a CAA refusal. Test it directly against your nameservers:
dig CAA example.com @ns1.your-dns-provider.net
A healthy answer is NOERROR, with or without records. SERVFAIL or a timeout means the DNS server is the problem, not your records.
Managed certificates and CDNs
Platforms that issue certificates on your behalf need their CA in your CAA set:
- AWS Certificate Manager certificates (CloudFront, load balancers) need one of the Amazon identifiers.
- Cloudflare edge certificates are issued by several CAs, currently including Let’s Encrypt and Google Trust Services. When you add CAA records to a Cloudflare zone, Cloudflare adds entries for the CAs its Universal SSL uses; look at the record list after saving to confirm what’s there, and keep those entries unless you’ve moved to a certificate you manage yourself.
- Any SaaS on a CNAME, as above.
Lock-in is the risk. A CDN that reissues from a different CA during an incident, or a platform that changes CAs, fails against a CAA set that only names the old one. That isn’t a reason to skip CAA, but it is a reason to list two CAs where the platform documents two, and to watch renewals.
A sensible rollout
- Inventory current issuers: the SSL check on each hostname, plus a Certificate Transparency search for your domain.
- List every CNAME to an outside service and find out which CA each uses.
- Lower the TTL on the apex (300 seconds is fine) a day ahead.
- Publish
issueentries for every CA you found,issuewildonly if you want to restrict wildcards differently, andiodefif you like. - Run a test issuance or renewal (
certbot renew --dry-runuses Let’s Encrypt’s staging CA, which checks CAA the same way) and walk the tree once more. - Raise the TTL again.
For the wildcard side of this, see wildcard certificates. For keeping renewals from silently failing after a change like this, see the expiry checklist.
Check your own domain now
Free, no sign-up. Runs the exact check this guide describes and shows what to fix.