Skip to content

SQS queues should have a dead-letter queue configured

When a consumer fails to process a message, SQS returns it to the queue for redelivery. Without a DLQ, poison messages cycle indefinitely, consuming compute, inflating costs, and blocking legitimate traffic. A DLQ captures these failures so you can inspect the message payload, replay it after fixing the bug, or alert on accumulation.

Silent message loss is worse than a noisy failure. Configuring a DLQ with an appropriate maxReceiveCount (typically between 3 and 5) gives your application a bounded retry window before isolating the problem message. That directly cuts mean-time-to-resolution for production incidents involving message processing failures.

Retrofit consideration

Each existing queue needs a corresponding DLQ created and a redrive policy attached. FIFO queues require a FIFO DLQ. At scale, that means auditing every queue and provisioning matching DLQs with correct naming and encryption settings before you can apply the policy without errors.

Implementation

Choose the approach that matches how you manage Terraform.

If you use terraform-aws-modules/sqs/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "sqs" {
  source  = "terraform-aws-modules/sqs/aws"
  version = ">=5.0.0"

  fifo_queue = false
  name       = "abc123"
}

Use AWS provider resources directly. See docs for the resources involved: aws_sqs_queue.

resource "aws_sqs_queue" "this" {
  name           = "pofix-abc123"
  redrive_policy = jsonencode({ deadLetterTargetArn = "arn:aws:sqs:us-east-1:123456789012:example-queue", maxReceiveCount = 5 })
}

What this control checks

The policy checks each aws_sqs_queue resource for a redrive policy directing failed messages to a DLQ. Two configuration paths are accepted: the aws_sqs_queue_redrive_policy resource, which takes queue_url and a policy JSON string containing deadLetterTargetArn and maxReceiveCount, or the redrive_policy argument set directly on aws_sqs_queue. To pass, deadLetterTargetArn must reference an existing SQS queue ARN and maxReceiveCount must be an integer from 1 to 1000. It fails when neither a redrive_policy argument nor a corresponding aws_sqs_queue_redrive_policy resource exists for the queue. The DLQ must be a separate aws_sqs_queue resource; FIFO queues require a FIFO DLQ with a name ending in .fifo.

Common pitfalls

  • FIFO queue requires a FIFO DLQ

    If your source queue has fifo_queue = true, the dead-letter target must also be a FIFO queue. Pointing a FIFO queue's redrive policy at a standard DLQ causes an API error at apply time. The DLQ aws_sqs_queue resource must also set fifo_queue = true with a name ending in .fifo.

  • maxReceiveCount set too high or too low

    Setting maxReceiveCount to 1 routes messages to the DLQ after a single failure, which is too aggressive for transient errors like a brief downstream timeout. Setting it near 1000 effectively defeats the DLQ. Most workloads are well-served by a value between 3 and 5.

  • DLQ retention period shorter than source queue

    Messages expire from the DLQ before anyone can investigate them if message_retention_seconds is shorter than the source queue's retention period. Set DLQ retention to at least 14 days (1209600 seconds) to give engineers a realistic window to respond.

  • Inline redrive_policy JSON conflicts with separate resource

    Using both the redrive_policy argument on aws_sqs_queue and a separate aws_sqs_queue_redrive_policy resource for the same queue causes perpetual drift. Pick one approach and use it consistently across your codebase.

  • DLQ itself has no monitoring

    Configuring a DLQ satisfies this control, but without a CloudWatch alarm on ApproximateNumberOfMessagesVisible for the DLQ, failed messages accumulate unnoticed. The DLQ only helps if someone watches it.

Audit evidence

The primary evidence artifact is AWS Config managed rule sqs-dead-letter-queue-enabled evaluation results showing all queues as COMPLIANT. CLI output from aws sqs get-queue-attributes --attribute-names RedrivePolicy for each queue should return a JSON object with deadLetterTargetArn and maxReceiveCount populated. CloudWatch metrics on the DLQ (ApproximateNumberOfMessagesVisible) confirm the DLQ is active.

CSPM scan reports should list each queue with its redrive policy status. Where CloudWatch alarms are configured on DLQ depth, the alarm configuration works as evidence of operational follow-through beyond the baseline configuration check.

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: sqs_queue_dead_letter_queue_configured

  • AWS Config Managed Rule: SQS_QUEUE_DLQ_CHECK

  • Powerpipe Control: aws_compliance.control.sqs_queue_dead_letter_queue_configured

Last reviewed: 2026-03-09