By default, any of the dozens of certificate authorities in a browser's trust store can issue a certificate for your domain. Nothing stops an attacker from walking up to a CA you have never used and requesting one in your name, as long as they can pass that CA's domain validation. A CAA record narrows the field to the CAs you actually authorize. It is one DNS record, and every public CA has been required to honor it since 2017.
What a CAA Record Does
CAA stands for Certification Authority Authorization, defined in RFC 8659, which obsoleted the original RFC 6844. Since CA/Browser Forum Ballot 187 took effect on 8 September 2017, every publicly trusted CA must check CAA before it issues. If a record exists and does not list the CA, the CA refuses.
The check happens at the CA, at the moment of issuance. A CAA record does nothing at the browser and has no effect on a certificate that is already live. It is a guard against mis-issuance, sitting upstream of every client.
The simplest record is one line:
example.com. IN CAA 0 issue "letsencrypt.org"
That authorizes Let's Encrypt and no one else. The leading 0 is the flags octet; issue is the property tag. Three tags carry the policy:
| Tag | What it controls |
|---|---|
issue |
Which CAs may issue certificates for the domain |
issuewild |
Which CAs may issue wildcard (*.) certificates; takes precedence over issue for wildcards |
iodef |
A URL where a CA may report a request that violated the policy |
A real-world record usually names more than one CA:
example.com. IN CAA 0 issue "letsencrypt.org"
example.com. IN CAA 0 issue "digicert.com"
example.com. IN CAA 0 issuewild "digicert.com"
example.com. IN CAA 0 iodef "mailto:security@example.com"
Let's Encrypt and DigiCert may both issue. Wildcards are the trap: once an issuewild tag is present it takes over for *. names, so here only DigiCert can issue a wildcard even though Let's Encrypt can issue everything else. The issuer strings are not hostnames you make up. Each CA publishes the exact value it matches against: Let's Encrypt is letsencrypt.org, DigiCert is digicert.com, Google Trust Services is pki.goog, Amazon is amazon.com. Get the string wrong and the CA reads itself as unauthorized.
Checking What a Domain Publishes
One query reads the record back. Apple publishes all three tags, which makes it a clean example:
$ dig CAA apple.com +short
0 issue "pki.apple.com"
0 issuewild "pki.apple.com"
0 iodef "mailto:contact_pki@apple.com"
An empty response means the name has no CAA record, which means every CA is allowed. If you would rather not parse raw dig output, the mrdns.com DNS lookup tool queries CAA directly.
How a CA Walks the Tree
This is the part people get wrong. A CA does not only check the name on the certificate. It checks that exact name, and when there is no record there it climbs one label at a time toward the apex, stopping at the first CAA record it finds. A request for www.a.b.example.com runs this sequence:
CAA www.a.b.example.com. → no record
CAA a.b.example.com. → no record
CAA b.example.com. → no record
CAA example.com. → 0 issue "letsencrypt.org" match, stop
The walk halts at the first name with a CAA record set and never reaches the root. So a record at your apex covers every subdomain, and a subdomain overrides the apex only by publishing its own. Put the policy at the apex and one line governs the whole zone.
Blocking Every CA
To forbid all issuance, publish an issue tag whose value is a single semicolon and nothing else:
secure.example.com. IN CAA 0 issue ";"
An issue tag restricts issuance to the CAs it names. Name none and it restricts issuance to no one. This is what you want on a hostname that should never carry a public certificate: an internal-only name, a parked label, a service behind a private CA. People reach for an empty string or a made-up value and get it subtly wrong. The bare ; is the spec's way to say no CA, full stop.
What the Rejection Looks Like
When CAA forbids issuance the CA does not issue, and the ACME client fails the order. Let's Encrypt returns:
Certification Authority Authorization (CAA) records
forbid the CA from issuing a certificate
If that turns up on a renewal that used to work, the usual cause is a CAA record listing a different CA than the one your automation switched to.
Why It Is Worth the One Line
Mis-issuance is a real failure mode. A certificate issued for your domain by a CA you do not use, through a validation flaw or a compromised account, is a certificate an attacker can present as you. CAA cuts the set of CAs that can produce one from the entire trust store down to the few you named.
It also turns a policy into an enforced control. If your team standardized on two CAs, a CAA record makes that binding: anyone grabbing a certificate from an unapproved CA is refused at issuance, and the shadow process surfaces on the spot instead of at the next audit. One note on iodef: CAs are not required to act on it, and the Baseline Requirements only say they should attempt to dispatch a report, so treat it as a best-effort courtesy signal and build your real alerting elsewhere.
Publish Without Breaking Renewals
The one way to hurt yourself is to lock out a CA you depend on. Inventory first. List every CA that issues for the zone: your main web certificates, anything a cloud provider auto-provisions, certificates a third party issues on a delegated subdomain, any internal automation. Confirm each issuer's exact identifier string. Then publish a record naming all of them, read it back with dig, and let one full renewal cycle complete before you call it done.
CAA restricts who can issue. It does not tell you what an authorized CA actually issued, and it cannot stop a CA that ignores the rules. Certificate Transparency logs cover that gap, and the two belong together: we walk through the detection side in Certificate Transparency monitoring. Generator Labs certificate monitoring tracks issuance and expiry across your domains so an unexpected certificate does not sit unnoticed. Start here.