serverlessawssqscost-optimization

Dead letter queue cost: what failure handling adds to the bill

Dead letter queues look free until a poison message or a bad deploy fills them. The cost is in redrive traffic, retry amplification, and storage of messages nobody reads. Here is the real arithmetic.

The C3X Team··6 min read

Quick answer

A dead letter queue bills exactly like a normal SQS queue: $0.40 per million requests for standard, $0.50 per million for FIFO, with every 64 KB chunk counted as a separate request. The queue itself is cheap; the failures that fill it are not. A message that fails its maxReceiveCount of 5 has consumed 5 receives, 5 Lambda invocations, and 5 full executions before landing in the DLQ, so one poison message can cost 10 times a successful one. A bad deploy that fails 10 million messages costs about $4 in queue operations but $80 or more in wasted Lambda duration and downstream calls, plus redrive charges when you replay them.

Dead letter queues are the part of an event-driven system that gets designed once and then forgotten until something goes wrong. That is exactly when they become expensive. The queue itself costs almost nothing. The failure path that feeds it costs multiples of the happy path, and the redrive that empties it costs again.

The direct queue charges

ItemRate
SQS standard requests$0.40 per million (first 1M free monthly)
SQS FIFO requests$0.50 per million
Payload chunkingEach 64 KB counts as one request
Message retentionNo storage charge, up to 14 days
SNS DLQ deliveriesBilled as SQS requests on the target queue

There is no per-GB storage fee on SQS, so a DLQ holding 2 million messages for 14 days costs nothing to keep. That is good news and bad news: good because retention is free, bad because nothing on the bill nudges you to deal with the backlog.

Retry amplification is the real cost

A message does not go to the DLQ on first failure. With a typical maxReceiveCount of 5, it is received and processed 5 times first. Each attempt is a receive request, a Lambda invocation, a full billed duration, and whatever downstream calls the function makes before failing.

Cost elementSuccessful messageMessage that reaches DLQ (5 attempts)
SQS receive + delete2 requests6 requests
Lambda invocations15
Lambda duration (512 MB, 300 ms)0.15 GB-s0.75 GB-s
Downstream API or DB calls1 setUp to 5 sets
CloudWatch error logsMinimal5 stack traces

Put volume behind that. Ten million messages fail during a bad deploy window. Queue operations: 60 million requests at $0.40 per million is $24. Lambda: 50 million invocations at $0.20 per million is $10, plus 7.5 million GB-seconds at $0.0000166667 is $125. Logging 5 stack traces each at roughly 2 KB is 100 GB ingested at $0.50 per GB, another $50. The incident costs over $200 in direct charges, and the DLQ line item is the smallest part of it.

Timeouts make it much worse

Failures that throw immediately are cheap. Failures that time out are not. A function with a 30 second timeout that hangs on a dependency burns the full 30 seconds on every one of its 5 attempts, which is 150 seconds of billed duration per message. At 512 MB that is 75 GB-seconds, or $0.00125 per message. One hundred thousand such messages cost $125 in duration alone, compared to $0.83 if they had failed fast. Setting a timeout close to realistic p99 duration is one of the highest-leverage cost controls in an event-driven system.

Redrive costs too

Replaying a DLQ sends every message back through the source queue and the consumer. Redriving 10 million messages costs another round of SQS requests, another 10 million Lambda invocations, and another full set of durations. If the underlying bug is not fixed, those messages fail again, consume another 5 attempts each, and return to the DLQ, doubling the incident cost. Always fix first, then redrive, and redrive in batches so you can confirm success before committing the full backlog.

On-failure destinations as a cheaper path

For asynchronous invocations, Lambda destinations can route failures to SQS, SNS, EventBridge, or another function, and they carry more context than a raw DLQ message: the original payload, the error, and the request id together. That richer record matters for cost because it often removes the need to replay a message just to discover why it failed. Reproducing a failure by redriving 100,000 messages through the consumer costs a full round of invocations and duration; reading the error from a destination record costs the storage it sits in. Destinations bill only as the target service does, so an EventBridge destination costs $1.00 per million events and an SQS destination $0.40 per million requests, the same rates as any other use.

Cheap guardrails

Lower maxReceiveCount for failures that are unlikely to be transient. Three attempts catch genuine blips; five or ten mostly multiply the cost of deterministic bugs. Use partial batch responses so a single bad record in a batch of 10 does not force all 10 to be retried. Keep timeouts tight. Filter obviously invalid messages at the edge before they reach the expensive consumer. Alarm on DLQ depth, since a growing DLQ is a cost signal as much as a reliability signal. And size retention deliberately: 14 days is the default habit, but a shorter window forces the conversation about what to do with the backlog. The samequeue pricing mechanics apply throughout. Price the queue and consumer together against the resource catalog so the failure path is budgeted, not discovered.

FAQ

Do dead letter queues cost extra on AWS?

A DLQ is billed as an ordinary SQS queue: $0.40 per million requests for standard queues, $0.50 per million for FIFO, with each 64 KB of payload counted as a separate request. There is no storage charge for retained messages up to the 14 day maximum, so the queue itself is inexpensive. The cost is in the failed processing that fills it.

Why do failed messages cost more than successful ones?

Because a message only reaches the DLQ after exhausting maxReceiveCount, typically 5 attempts. Each attempt is a receive request, a Lambda invocation, a full billed duration, and any downstream calls made before the failure. A message that reaches the DLQ therefore costs roughly five times the compute of a successful one, plus extra queue operations and error logging.

How much can a bad deploy cost through a DLQ path?

Ten million messages failing five times each generates 60 million SQS requests at about $24, 50 million Lambda invocations at $10, roughly 7.5 million GB-seconds at about $125 for a 512 MB function running 300 ms, and around $50 in CloudWatch Logs ingestion for the stack traces. That is over $200, with the DLQ itself the smallest component.

How do timeouts amplify dead letter queue cost?

A function with a 30 second timeout that hangs burns the full 30 seconds on each of five attempts, which is 150 billed seconds per message. At 512 MB that is about $0.00125 per message, so 100,000 such messages cost roughly $125 in duration alone against $0.83 if they had failed fast. Tight timeouts are a major cost control.

Does redriving a dead letter queue cost money?

Yes. Redrive sends every message back through the source queue and consumer, generating another full round of SQS requests, Lambda invocations, and duration charges. If the underlying bug is unfixed, those messages fail their retries again and return to the DLQ, doubling the incident cost. Fix the cause first and redrive in batches to confirm success.

How does C3X help with dead letter queue cost?

C3X prices queues, functions, and their configuration from Terraform, so the messaging and compute sides of an event pipeline appear together before deployment. Retry settings, timeouts, and batch sizes defined in Terraform become visible cost decisions in the pull request, which is where a maxReceiveCount of 10 and a 30 second timeout are cheapest to reconsider.

What to do next

Budget the failure path, not just the happy path. C3X reads your Terraform and prices your resources against a live catalog. Start with the quickstart.

Try C3X on your own Terraform

Free and open source. No API key required. One command to install, one command to estimate.