</>CodeWithKarani

"Too Many Certificates Already Issued": Fixing Let's Encrypt Rate Limits

Karani GeoffreyKarani Geoffrey8 min read

The certificate expired, the site is throwing a browser warning, and the one command that has always fixed this now refuses to run. So you run it again. Then you try --force-renewal. Then you delete /etc/letsencrypt and start clean. Then you install acme.sh, because maybe certbot is the problem.

Every one of those moves makes the situation worse, and the last one is the most expensive, because it feels like progress. The duplicate certificate limit is enforced by Let's Encrypt's servers against the exact set of names you are asking for, and it is global across every ACME account. Changing clients, changing accounts, changing servers, reinstalling the OS: none of it moves the counter.

Stop running certbot. That is the actual first step. The counter you have exhausted refills on a schedule that has nothing to do with how many times you retry, and the retries can get your account paused on a different limit entirely.

You hit the duplicate certificate limit: 5 certificates per exact set of identifiers per 7 days, global across all accounts, with no overrides available.

  • Check whether you already have a valid certificate on disk before treating this as an emergency: certbot certificates.
  • Look up your real issuance history at crt.sh to see exactly when the oldest of the five ages out. The bucket refills roughly one certificate every 34 hours, so you usually wait hours, not a week.
  • To get a certificate right now, request a different set of names, for example add www. A different exact set is a different bucket.
  • Do all further experimenting against --staging, or certbot renew --dry-run, which uses staging automatically.

The exact errors

Two wordings are in circulation depending on how the failure reaches you. Both are the same limit:

too many certificates already issued for exact set of domains: example.com
Error creating new order :: too many certificates (5) already issued for this
exact set of domains in the last 168 hours: example.com, retry after 2026-07-25T09:14:00Z

Its close relative, which is a completely different bucket and needs a different response:

too many certificates (50) already issued for example.com in the last 168 hours

Why this happens

Let's Encrypt runs several independent rate limits and the message tells you which one you tripped. Confusing them is why so much of the advice online is useless.

LimitValueRefillOverrides
New certificates per exact set of identifiers5 per 7 days1 roughly every 34 hoursNone offered
New certificates per registered domain50 per 7 days1 roughly every 202 minutesAvailable on request
New orders per account300 per 3 hours1 every 36 secondsAvailable on request
Authorization failures per identifier per account5 per hour1 every 12 minutesNone

Three properties of the duplicate limit do the real damage.

It is keyed on the exact set of identifiers. A certificate for example.com and a certificate for example.com, www.example.com occupy different buckets. Same domain, different set, independent counters.

It is global. It applies across all ACME accounts, not per account. This is the fact that kills the most popular workaround. Switching from certbot to acme.sh, registering a new account, or moving to a new server changes nothing, because the counter lives on Let's Encrypt's side and is keyed on the names you are asking for.

It refills continuously, not all at once. You are not waiting seven days from now. You are waiting until the oldest of your five issuances is more than 168 hours old, which is why the retry-after timestamp in the error is usually hours away rather than days. If you issued three certificates on Monday afternoon while debugging, the bucket starts giving them back on the following Monday afternoon, one at a time.

The bucket does not empty and refill. It ages out one slot at a time. Mon 14:02 Mon +168h 5 issuances in 40 minutes of debugging Meanwhile, a different set of names is a different bucket example.com is full. example.com + www.example.com has all 5 slots free. That is the legitimate emergency exit, and it costs you one slot from the 50 per week per domain.
The retry-after timestamp in the error is the moment the oldest issuance crosses 168 hours, which is nearly always sooner than a full week.

The fix

Step 1: Check whether you actually need a new certificate

A surprising number of these incidents are not certificate problems. The certificate on disk is valid and the web server is serving an old one, or serving the wrong lineage.

certbot certificates
Found the following certs:
  Certificate Name: example.com
    Serial Number: 3f8a...
    Domains: example.com www.example.com
    Expiry Date: 2026-09-14 08:22:11+00:00 (VALID: 51 days)
    Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem

If it says VALID with days remaining, you have no issuance problem at all. Point your server at that path and reload. Compare what is on disk with what is actually being served:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates -subject

Step 2: Find out what you have already been issued

Go to crt.sh and search for your domain. Certificate Transparency logs are the authoritative record, and they will show you five entries you had forgotten about, usually from a control panel or a second server also running certbot against the same names. The timestamp on the oldest entry, plus 168 hours, is when your next slot opens.

Step 3: Move all experimentation to staging

This is the discipline that prevents the whole problem. The staging environment has much higher limits and issues certificates from an untrusted root, which is fine for testing that your challenge, your webroot and your hooks all work:

certbot certonly --staging --cert-name example.com \
  -d example.com -d www.example.com \
  --webroot -w /var/www/html

For an existing lineage, certbot renew --dry-run runs the full renewal against staging without touching your live files. Get a clean dry run before you spend a production slot. Delete the staging certificate afterwards with certbot delete --cert-name example.com so it does not confuse your live configuration.

Step 4: If you need a certificate right now, change the identifier set

Since the limit is keyed on the exact set, requesting a different set gives you a fresh bucket. Adding www is the usual move, and it is a set you probably wanted anyway:

certbot certonly --cert-name example.com \
  -d example.com -d www.example.com --expand \
  --webroot -w /var/www/html

--cert-name keeps everything under the same lineage, so /etc/letsencrypt/live/example.com/ stays the path your nginx config already points at. --expand tells certbot you meant to change the name list rather than warning you about it. This spends one slot from the 50 per registered domain per week, so it is an escape hatch, not a strategy: do it four or five times in a week and you will hit the other limit, which is much less pleasant.

Step 5: Consolidate so it cannot recur

Most repeat offenders have accumulated three or four overlapping lineages, each renewing on its own timer, each burning slots. Look at what exists:

ls /etc/letsencrypt/renewal/

One certificate with all the SAN names on it, one renewal config, one timer. Delete the duplicates with certbot delete --cert-name <old>. Then make sure the renewal is actually automatic and does not depend on someone remembering, because manual renewal is what produces the 3am debugging session that fills the bucket in the first place. My notes on installing certificates on a server cover the webroot and reload hook setup.

Finally, prefer an ACME client that supports ACME Renewal Information. Let's Encrypt exempts ARI-coordinated renewals from all rate limits, which makes the whole class of problem go away. Check your client's documentation for whether it queries the renewal info endpoint.

Verification

certbot renew --dry-run
Congratulations, all simulated renewals succeeded:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

Then confirm the served certificate matches what is on disk, and that the chain is complete:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -enddate -ext subjectAltName

Check the SAN list contains every name you serve. A missing www here is the single most common cause of "it works for me" reports where half your users see a warning. Finally, check the renewal timer is armed:

systemctl list-timers 'certbot*'

What people get wrong

Switching ACME clients. Moving from certbot to acme.sh or lego does not reset anything. The duplicate limit is enforced by Let's Encrypt against the set of names, across all accounts. You will burn an hour on a new client and get the identical error.

Deleting /etc/letsencrypt to "start clean". This is the most destructive advice in circulation. It throws away the account key, the renewal configuration, and any valid certificates you still had, including ones that were not affected. You then cannot reissue, because the limit is server-side, and you no longer have the working certificate you could have kept serving.

--force-renewal in a cron job. If it is in your crontab, remove it now. It renews unconditionally on every run, which will quietly consume five slots a week for every certificate and guarantee this error the day you actually need an emergency reissue. Plain certbot renew is a no-op until the certificate is near expiry, which is exactly what you want.

Believing you have to wait a full week. Read the retry-after timestamp in the error. It is usually the same day or the next one.

Retrying in a loop while you wait. Order attempts that fail validation count against a separate authorization-failure limit, and sustained consecutive failures can get the account paused. A failed loop turns a several-hour wait into a much worse problem.

When it is still broken

  • The error names the 50 per registered domain limit instead. Different problem. "Registered domain" means the public suffix plus one label, so every subdomain shares it. Consolidate subdomains onto fewer certificates using SANs, or move to a wildcard, which requires the DNS-01 challenge and API access to your DNS provider. Overrides for this limit can be requested from Let's Encrypt.
  • You are on a dynamic DNS or shared hosting subdomain. If your name sits under a provider's domain, you may be sharing a rate-limit bucket with every other customer on it. There is nothing to fix on your side. Use your own domain.
  • You genuinely cannot wait. Nothing stops you using a different CA temporarily. ZeroSSL and Buypass both speak ACME and certbot can point at them with --server. Their limits are independent of Let's Encrypt's.
  • Validation is failing, not issuance. If the message is about authorization or challenges rather than certificate counts, the rate limit is a symptom. Fix the challenge first: for HTTP-01 that usually means a redirect or a firewall rule blocking /.well-known/acme-challenge/, which is worth checking against your reverse proxy configuration before you spend another slot.

The whole class of problem comes down to one habit. Treat production issuance as a limited resource you spend deliberately, and do every experiment against staging. Five attempts a week sounds generous until the night you need three of them in ten minutes.

Frequently asked questions

How long do I have to wait after hitting the Let's Encrypt duplicate certificate limit?
Not a full week in most cases. The limit allows 5 certificates per exact set of identifiers per 7 days and the bucket refills roughly one slot every 34 hours as old issuances age past 168 hours. The retry-after timestamp in the error message is the exact moment your next slot opens, and crt.sh shows the issuance timestamps it is calculated from.
Will switching from certbot to acme.sh get around the rate limit?
No. The duplicate certificate limit is enforced by Let's Encrypt's servers against the exact set of names requested, and it applies globally across all ACME accounts. Changing client, account, or server does not move the counter, and no override is offered for this particular limit.
Can I get a certificate immediately after hitting the limit?
Yes, by requesting a different exact set of names, since each distinct set has its own bucket. Adding www to a certificate that previously covered only the bare domain is the usual move, using certbot certonly --cert-name example.com -d example.com -d www.example.com --expand. It consumes one slot from the separate 50 per registered domain per week limit.
Is it safe to delete /etc/letsencrypt and start again?
No, and it is the most damaging thing you can do here. The rate limit lives on Let's Encrypt's servers, so deleting local files changes nothing about your ability to issue, while destroying your account key, your renewal configuration and any valid certificates you could still have been serving.
#Let's Encrypt#Certbot#TLS#ACME#Nginx
Keep reading

Related articles