DynamoDB Throttling — Why It Happens and How to Fix It
Throttling is DynamoDB telling you a limit was hit — but there are four different limits, three different exceptions, and the fix for one cause makes another worse. Raising table capacity does nothing for a hot key; switching to on-demand does nothing for a hot key either and can still throttle on its own rules. This guide is the umbrella: which limit you actually hit, how the metrics tell them apart, and the fix that matches each cause.
Why is DynamoDB throttling my requests?
One of four documented reasons: a single partition exceeded its fixed per-partition limit of 3,000 read units or 1,000 write units per second (a hot key — happens in both capacity modes); the table exceeded its provisioned RCU/WCU (provisioned mode); the account exceeded its region-level throughput quota; or an on-demand table grew faster than double its previous peak within 30 minutes. The fix depends on which one it was, so diagnose before you resize anything.
The four throttling scenarios
AWS's own troubleshooting page splits throttling into exactly four cases:
- Key-range (partition) throughput exceeded — both modes. Every partition is designed for a maximum of 3,000 read units and 1,000 write units per second (partition-key docs), and item size counts against it. No table-level setting raises this; only key design spreads it. This is the hot partition case, and the table can look massively under-utilized while it throttles.
- Provisioned throughput exceeded — provisioned mode. Consumption beat the table's (or a GSI's) provisioned RCU/WCU, and the ~5-minute burst-capacity cushion was spent. The fix ladder is capacity-side: auto scaling, a higher provision, or a mode switch.
- Account-level quota exceeded. Regional account quotas cap total throughput — by default 40,000 read and 40,000 write units per table, and for provisioned mode 80,000 RCU and 80,000 WCU per account (quotas); these are initial defaults, adjustable via Service Quotas, and on-demand tables have no account-level throughput quota.
- On-demand maximum throughput exceeded. On-demand instantly accommodates up to double the previous peak; grow past double within 30 minutes and it can throttle (on-demand docs). New on-demand tables sustain 4,000 writes/s and 12,000 reads/s out of the box. For a planned step-spike (launch, sale, migration), pre-warm the table with warm throughput instead of hoping the ramp is gradual.
The three exceptions, and the field that names the cause
ProvisionedThroughputExceededException— provisioned-mode capacity throttling: "you exceeded your maximum allowed provisioned throughput for a table or for one or more global secondary indexes". Details on the dedicated error page.ThrottlingException— control-plane operations issued too fast, and, on on-demand tables, any data-plane operation whose rate is too high (that's the exception behind the double-peak rule — see the on-demand error page and ThrottlingException).RequestLimitExceeded— account-level throughput limits: "contact AWS Support" territory, covered on its error page.
All three are marked retryable, and all three now carry structured
ThrottlingReason values of the form resource + operation + limit —
TableReadProvisionedThroughputExceeded,
IndexWriteKeyRangeThroughputExceeded, TableWriteAccountLimitExceeded, and so
on (error reference).
Read the reason, not just the exception class: it names the resource (table or
index), the operation direction, and which of the four limits you hit — which is
exactly the diagnosis. One hedge the docs themselves force: AWS pages differ on
whether account-limit throttling surfaces as RequestLimitExceeded or a
ThrottlingException with an AccountLimitExceeded reason, so key your
handling on the reason string.
What absorbs load before you're throttled
Two built-ins soften limits, and knowing their edges explains "it worked yesterday":
- Burst capacity retains up to five minutes (300 seconds) of unused read and write capacity for spikes — but DynamoDB may also consume it for background maintenance "without prior notice", and AWS explicitly notes the details may change. Don't design for burst; treat it as luck.
- Adaptive capacity automatically and instantly shifts throughput toward hot partitions and can isolate a frequently-accessed item onto its own partition — but only "provided that traffic does not exceed your table's total provisioned capacity or the partition maximum capacity". It rebalances skew; it never lifts the 3,000/1,000 per-partition ceiling, and it won't split item collections when the table has an LSI. The current AWS troubleshooting pages lean on split-for-heat — partitions splitting under sustained heat — which takes time and does not help a single hot key.
Diagnose it from the metrics
CloudWatch separates requests from events, and the distinction does the diagnosis (metrics reference):
ThrottledRequestscounts a request once if any event inside it was throttled — aPutItemon a table with three GSIs is one request but four write events. In a batch, it increments only if every item throttled.ReadThrottleEvents/WriteThrottleEventscount each throttled event — aBatchGetItemof 10 items is 10GetItemevents. To see a GSI's write throttles you must query the metric with bothTableNameandGlobalSecondaryIndexName— this is how GSI back-pressure hides from table-level dashboards.- The newer reason-specific event metrics
(
WriteProvisionedThroughputThrottleEvents,ReadKeyRangeThroughputThrottleEvents,…AccountLimitThrottleEvents,…MaxOnDemandThroughputThrottleEvents) split the counts by the same four causes — if your region shows them, they answer the "which limit" question directly.
One trap: SDKs retry throttled requests automatically — the standard retry mode makes 3 total attempts by default (the 2026 opt-in retry rollout moves DynamoDB clients to 4 attempts with tighter delays). Light throttling therefore shows up as latency, not errors; watch the throttle metrics, not just your exception logs.
GSI back-pressure: the throttle that points at the wrong table
If any GSI can't absorb the write amplification, "DynamoDB throttles writes to
the base table to maintain data consistency"
(GSI throttling docs)
— even when the base table has capacity to spare. The exception's ResourceArn
points at the index, but the operation that failed is your base-table write.
Every index needs its own capacity plan (and its own
auto-scaling policy);
why a GSI throttles base-table writes
walks through the mechanics.
Match the fix to the cause
| Cause | What fixes it | What doesn't |
|---|---|---|
| Hot key / partition | Key design that spreads load (hot partitions); time for split-for-heat | Raising table capacity, switching to on-demand |
| Provisioned capacity | Auto scaling, higher min, or on-demand | Retries alone — they add load |
| GSI back-pressure | Scale the index; sparse-index or projection changes | Scaling the base table |
| Account quota | Service Quotas increase | Table-level settings |
| On-demand step spike | Pre-warm (warm throughput); spread the ramp over 30+ min | Waiting — double-peak resets slowly |
Do it in DynoTable
Most self-inflicted throttling starts with reads that cost more than they look:
a filtered Scan consumes the full read either way. DynoTable's pre-run cost
preview shows whether a statement becomes a Query or a Scan, the index it
hits, and an estimated read cost before you spend it — the cheapest throttling
fix is the expensive read you didn't run. The
Scan vs Query guide covers the difference; the free
item size calculator turns a real item
into the RCU/WCU numbers the limits above are measured in.
Pitfalls and next steps
- Retries amplify overload. Backoff is built into the SDKs, but a tight application-level retry loop on top of SDK retries multiplies pressure on exactly the partition that's struggling.
- Batches hide partial throttling. A
BatchWriteItemreturns unprocessed items rather than throwing while any item succeeds — checkUnprocessedItems, not just exceptions. - The table-level view lies about GSIs. Always chart throttle events per-index; base-table dashboards look clean during back-pressure.
- Capacity fixes take minutes; key design is forever. Auto scaling reacts in ~5 minutes, quota increases take a support ticket, but a hot key follows you to every capacity mode — spend the effort where it compounds: how partition keys work.
Download DynoTable to see each query's Scan-vs-Query plan and read cost before it runs against your capacity.