Most systems track a delivery or receive count per message. With Amazon SQS you set a redrive policy with a maxReceiveCount, for example 5. Each time a consumer receives the message but does not delete it before the visibility timeout expires, SQS increments the count. On the 6th receive it moves the message to the DLQ you named instead of handing it back.
RabbitMQ does it differently. A message becomes dead-lettered when it is rejected with requeue=false, when it expires past its TTL, or when the queue hits its length limit. The broker then republishes it to a dead-letter exchange you configured on that queue, which routes it to your DLQ. Kafka has no built-in DLQ, so frameworks like Kafka Connect and Spring Kafka implement it by producing the failed record to a separate dead-letter topic, usually carrying the original headers plus the exception and stack trace.
A good DLQ entry keeps context: the original payload, the source queue, the failure count, the last error, and a timestamp. Once you fix the cause, you redrive or replay the messages back to the source queue so they get processed normally. SQS even ships a one-click redrive feature for exactly this.