Amazon SQS empty receive cost is what a quiet queue does to the request meter. ReceiveMessage is an API action. The SQS pricing page says every Amazon SQS action counts as a request. An empty response is still that action. The queue had nothing to return, and the call still counts. While the account is inside the free allotment, the empty calls hide. Past it, a tight short-poll loop is a request generator with no messages attached.
Rutagon finds this on workers that poll as fast as the runtime allows, and on health checks that receive from the queue to prove it is alive. Serverless cost optimization covers Lambda duration and memory. This article is the receive that returns nothing.
What Amazon SQS empty receive cost counts
SQS has no minimum fee. You pay for the requests you make. Every customer gets 1 million Amazon SQS requests free each month. The pricing page says some applications can stay inside that allotment. The free tier is calculated each month across all Regions except GovCloud, applied to the bill automatically, and unused free requests do not roll over. A quiet week does not bank requests for a noisy week.
The request table on the pricing page has two columns, standard queues and FIFO queues, both per million requests. The first 1 million requests in the month are free in both columns. Above that, the page prices bands: from 1 million to 100 billion, from 100 billion to 200 billion, and over 200 billion. The dollar rate in each band is a Region price on the page. We read the Region. We do not carry a rate from one Region onto another, and we do not invent one when the table has not been read. The meter is the same either way. Empty receives consume the free million, then they consume the paid bands.
FIFO is a different column. API actions for sending, receiving, deleting, and changing visibility on FIFO queues are charged at FIFO rates. Other API requests on those queues are charged at standard rates. A receive on a FIFO queue, empty or not, is a FIFO-rate request. Fair queues are a second case on standard queues: a request that touches a message with a group ID is charged fair-queue rates and standard rates. An empty receive has no message, so it stays on the one rate for that queue type.
A single request can carry 1 to 10 messages, up to a total payload of 1 MiB. Each 64 KB chunk of a payload bills as one request. The page's own illustration: an API action with a 1 MiB payload bills as 16 requests. Batching ten small messages into one receive is one request. One fat message can be many. Empty receives do not get a batching discount, because there is no payload to batch. They are one action, one request, repeated.
Same-Region data transfer into SQS and out of SQS is not charged. Cross-Region transfer and transfer to or from the internet use standard data transfer rates. A queue encrypted with a customer managed KMS key adds KMS requests on top of the SQS requests. The pricing page points that at KMS pricing. The empty receive and the KMS call are different lines. Fixing the poll loop does not shrink the KMS line, and caching a data key does not shrink ReceiveMessage.
Long polling against a tight short-poll loop
The short and long polling documentation is the control on empty responses. Short polling is the default. ReceiveMessage queries a subset of servers, chosen by a weighted random distribution, and returns immediately, including when no messages are found. A particular short-poll request can miss messages that sit on servers it did not sample. With fewer than 1,000 messages in the queue, a later request returns them. A loop that short-polls will eventually see the messages, and it will also see a lot of empty answers while it waits.
Long polling starts when the wait time on ReceiveMessage is greater than 0. The maximum wait is 20 seconds. SQS queries the servers and sends a response once at least one message is available, up to the maximum you asked for. An empty response is sent when the wait expires. The documentation says this reduces empty responses and can lower cost. It also reduces false empty responses, the case where messages exist and a short poll's partial sample missed them. Short polling is in effect when the call sets WaitTimeSeconds to 0, or when the call omits it and the queue attribute ReceiveMessageWaitTimeSeconds is 0.
call: ReceiveMessage
wait_time_seconds: 0 is short poll, 1 to 20 is long poll
empty_response: still one API action, still one request
free_tier: 1 million requests per month, all Regions except GovCloud, no rollover
batch: 1 to 10 messages, then each 64 KB chunk is another request A worker that loops with wait 0 and no sleep can issue a receive for every network round trip. At a few hundred empty receives a second, the free million is a few hours, not a month. One long poll of 20 seconds is one request for that quiet interval. Twenty seconds of short polling with no pause is as many requests as the loop can complete. The message, when it arrives, is returned by the long poll as soon as it is available. You do not wait out the full 20 seconds on a busy queue.
A low wait still leaves gaps. The documentation notes that a low ReceiveMessageWaitTimeSeconds can return empty even when the queue has messages. We set the wait near the 20 second maximum on consumers that are allowed to be idle, and we set a shorter wait only when a caller is holding a user request open. A web request that polls SQS with wait 0, in a retry loop, spends a receive on every iteration while the caller waits.
Lambda event source mappings poll for you. The mapping's batch window and batch size decide how many receives the service issues. A mapping on an idle queue still polls. We look at the queue's request count next to the number of messages sent. When receives dwarf sends, the consumer is polling air. When they match a long-poll cadence, the worker is waiting the way the API expects.
What we change on the worker
The diagnostic is the queue, the ReceiveMessageWaitTimeSeconds attribute, and the wait each consumer passes on the call. A queue attribute of 20 seconds does nothing for a caller that passes 0. The call wins. We read the code, not only the console. Cost Explorer shows SQS requests. It does not show which calls were empty. The ratio of receives to sends is the clue, and a metric filter on empty responses in the worker log makes it obvious.
The fix is a wait greater than 0, a batch size up to 10, and DeleteMessageBatch so ten deletes are one action. We take receives out of health checks. GetQueueAttributes is still a request, so the check hits the process and leaves the queue alone. We set the queue attribute and the client default to the same wait, so a new worker cannot boot on short polling by omission.
We leave a shorter wait when a person is staring at a status page and 20 seconds is too long. The loop still sleeps. A tight loop at wait 0 spends the free million on empty responses. Event-driven architecture is where the consumer belongs: one worker blocked on a long poll, or a Lambda mapping, with the database write downstream of a message that actually arrived.
GovCloud is outside the free-tier sentence. An account that spans commercial Regions shares one million free requests across those Regions. A second Region does not get its own million. We add the Regions before we tell anyone the worker is "still free."
Rutagon runs this as a short bill review: free-tier consumption, wait time on the call and on the queue, batch size, FIFO versus standard column, and any fair-queue group ID on the messages that do come back. The pricing page is the source for the free million, the request bands, and the rule that every action counts. The polling page is the source for the 20 second wait. If the Region rate changes, the question does not: how many ReceiveMessage calls returned nothing, and why was the wait zero?
Frequently Asked Questions
When does Amazon SQS empty receive cost actually show up?
The first 1 million SQS requests each month are free, across commercial Regions, and unused requests do not roll over. GovCloud is outside that sentence. Every ReceiveMessage counts, including the ones that return no messages. The charge appears once the account is past that million and the short-poll loop is still running.
Does long polling make the empty receive free?
Long polling cuts the number of empty responses. A wait from 1 to 20 seconds holds one request open until a message arrives or the wait ends, and that request still counts. Twenty seconds of quiet is one long-poll request, and the same twenty seconds of short polling with no sleep is a burst of requests.
Why did a batch size of 10 not help?
A batch holds 1 to 10 messages, up to 1 MiB, and each 64 KB chunk of payload bills as another request. An empty receive has no messages to batch, so the batch size never applies. Batching helps the hours when the queue is full. The idle hours are a wait-time problem.
Are FIFO empty receives priced like standard ones?
Send, receive, delete, and change-visibility on a FIFO queue use the FIFO column on the pricing page. The first million requests in the month are free in that column too. Above the free million, FIFO has its own per-million rate for the Region. An empty FIFO receive is still a receive, so it uses the FIFO rate once you are past the allotment.
Does encrypting the queue change the empty receive?
Server-side encryption with KMS adds KMS charges for SQS calls to KMS, which the SQS pricing page calls out separately. The SQS request for ReceiveMessage remains. Same-Region data transfer to and from SQS is not charged. Cross-Region transfer is its own data-transfer line.
Ask for an AWS bill review that counts empty receives against the free million. Contact Rutagon at rutagon.com/contact, 907-841-8407, or contact@rutagon.com.