How to stop one Athena query from scanning your whole CUR (2026)

Akal Cloud 6 min read

Quick answer

There are two controls and only one stops anything. The per-query data scanned limit cancels any query exceeding it, one per workgroup, settable from 10 MB to 7 EB, and the cancel action cannot be changed. The per-workgroup limit only raises an alert: AWS states queries are not automatically cancelled when a threshold is reached. Cancelled queries are still billed, and may leave partial results and incomplete multipart uploads in S3 that you must clean up.

Athena bills on bytes scanned, so a single careless SELECT * against a Cost and Usage Report can cost more than the report does to store. Athena has two built-in cost controls that address this, they behave completely differently, and only one of them actually stops anything.

What does a runaway query cost?

Athena pricing charges on data scanned, and works its example at $5 per TB. The same page shows the two levers that move that number, reporting "3x savings from compression and 4x savings for reading only one column" after converting a dataset to Parquet.

A CUR is exactly the shape that punishes carelessness: wide, with 125 possible columns in CUR 2.0, and long, particularly once split cost allocation data is adding tens of thousands of rows a day per cluster. Scanning all of it repeatedly, from a dashboard that refreshes on a timer, is how a query bill becomes a line item somebody asks about.

What are the two controls?

Per the per-query and per-workgroup data usage controls documentation: "Athena allows you to set two types of cost controls: per-query limit and per-workgroup limit. For each workgroup, you can set only one per-query limit and multiple per-workgroup limits."

Per-query limitPer-workgroup limit
MeasuresData scanned by one queryData scanned by all queries in a period
On breachCancels the querySends an alert. Cancels nothing.
How manyOne per workgroupMultiple per workgroup
PeriodPer queryHourly or daily aggregate
Configurable actionNo: "this setting cannot be changed"Yes: SNS, Lambda, disable the workgroup

The distinction in the second row is the one that costs money when it is misread. AWS is explicit about the workgroup limit: "Queries are not automatically canceled when a threshold is reached." It is an alarm, not a brake. If you configured a 1 TB daily workgroup limit believing it was a cap, you have a notification that your budget was exceeded, not a mechanism that prevented it.

The per-query limit is the one with teeth: "if any query that runs in the workgroup exceeds the limit, it is canceled", and "the default action is to cancel the query if it exceeds the limit. This setting cannot be changed."

How do you set the per-query limit?

On the workgroup's Execution controls tab, as a Data scanned limit. AWS documents the accepted range as "between 10 MB (minimum) and 7 EB (maximum)".

Pick the number from what your legitimate queries actually scan, not from what feels safe. A monthly CUR aggregate over one billing period scans far less than an unpartitioned full-table scan, and the gap between those two is where the limit belongs. If you do not know the figure, run your normal workload and read DataScannedInBytes, which QueryExecutionStatistics defines as "the number of bytes in the data that was queried", before choosing.

aws athena get-work-group --work-group awsinsights_cur \
  --query 'WorkGroup.Configuration.BytesScannedCutoffPerQuery'

WorkGroupConfiguration defines that field as "the upper data usage limit (cutoff) for the amount of bytes a single query in a workgroup is allowed to scan", with a valid range starting at 10,000,000 bytes, which is the 10 MB floor the console shows.

A null result means no per-query limit is set, which is the default and is worth checking on any workgroup that a dashboard or a scheduled job points at.

Do you pay for a query that gets cancelled?

Yes. This is the sentence that changes how you think about the limit: "Canceled queries are charged according to Amazon Athena pricing."

So the per-query limit caps your exposure rather than eliminating it. Set it at 1 TB and a runaway query costs you up to a terabyte of scanning before it dies. That is still far better than the unbounded alternative, but it means the limit is a circuit breaker, not a refund.

Athena's own metrics agree. The ProcessedBytes metric counts bytes scanned per DML query, and explicitly: "for queries that were canceled (either by the users, or automatically, if they reached the limit), this includes the amount of data scanned before the cancellation time." The bytes are counted, so they are billed.

There is a second, quieter cost. AWS notes that "in the case of canceled or failed queries, Athena may have already written partial results to Amazon S3. In such cases, Athena does not delete partial results from the Amazon S3 prefix where results are stored. You must remove the Amazon S3 prefix with partial results."

Those partial results are yours to clean up, and they accumulate silently in the results bucket. AWS recommends a specific remedy: "Athena uses Amazon S3 multipart uploads to write data to Amazon S3. We recommend that you set the bucket lifecycle policy to end multipart uploads in cases when queries fail." Incomplete multipart uploads are storage you are billed for and cannot see in the object listing, which makes them one of the better-hidden line items in S3.

It gets one turn worse: "under certain conditions, Athena may automatically retry query executions. In most cases, these queries are able to complete successfully and the query ID is marked as Completed. These queries might have written partial results during the initial attempts and may generate incomplete multipart uploads." So a query that shows as successful can still have left debris behind.

What can the workgroup alert actually do?

More than send an email, if you wire it up. The threshold sets "multiple thresholds on hourly or daily aggregates on data scanned by queries running in the workgroup", and on breach an SNS notification fires. From there AWS documents two escalations worth knowing:

  • Invoke a Lambda function, through an SNS subscription.
  • Disable the workgroup "to stop any further queries from running".

That second one is the missing brake. The workgroup limit cannot cancel a query, but an SNS-triggered Lambda that disables the workgroup stops the next one. It is a blunt instrument and it will interrupt legitimate work, so it belongs on a workgroup used by scheduled jobs rather than one people query interactively.

One race condition to be aware of, which AWS states directly: "if two or more users run queries at the same time in the same workgroup, it is possible that each query does not exceed any of the specified limits, but the total sum of data scanned exceeds the data usage limit per workgroup." Per-query limits do not compose into a per-workgroup guarantee.

Why separate workgroups at all?

Because the per-query limit is one per workgroup, and one number rarely fits every consumer. A dashboard issuing narrow, partitioned queries every fifteen minutes and an analyst doing exploratory work have completely different legitimate ceilings. Putting them in one workgroup forces the limit up to the analyst's needs, which leaves the dashboard unprotected.

Splitting by consumer also gives you per-consumer attribution, since WorkGroup is a documented dimension on Athena's AWS/Athena metrics, alongside QueryState (SUCCEEDED, FAILED or CANCELED) and QueryType. It also lets you disable one group's access without touching the other.

Those metrics are opt-in per workgroup rather than automatic: PublishCloudWatchMetricsEnabled "indicates that the Amazon CloudWatch metrics are enabled for the workgroup". If a workgroup's Metrics tab is empty, check that flag before concluding nobody is querying.

The controls are the last line, not the first

Every control here limits damage after a query is already scanning. The cheaper interventions come earlier and are all about scanning less:

  • Always filter on a partition column. A query with no partition predicate scans everything, whatever else is configured.
  • Never SELECT * on a CUR. Columnar storage means you are billed for the columns you name, so naming all 125 forfeits the entire benefit.
  • Use a columnar format. Athena's own example shows 3x from compression and 4x from reading one column.
  • Remove the catalog lookup too, with partition projection, which is free and eliminates the crawler.
  • Cache results in the application. The cheapest scan is the one that does not run: our own CUR queries go through a 15-minute cache, so a dashboard refresh costs nothing after the first hit.

Set the per-query limit anyway. It is a single number on a workgroup, it costs nothing, and it converts an unbounded mistake into a bounded one. Just do not mistake the workgroup threshold for the same thing.

See this on your own bill

Akal Cloud connects in about two minutes and shows the same numbers against your real AWS accounts.

Get started on AWS Marketplace

Related reading

  • How to query your CUR in Athena without a Glue crawler (2026)

    Partition projection computes partitions from table properties instead of calling GetPartitions, so a CUR table needs no crawler and no MSCK REPAIR TABLE. The configuration, and the six ways it returns zero rows instead of an error.

  • AWS Cost Categories: what split charge rules can and can't do (2026)

    Cost categories reorganise spend retroactively to the start of the month, which tags cannot. Split charge rules then divide shared cost across teams, but the result never leaves the console: it is absent from the CUR, Cost Explorer and Budgets.

  • Why Cost Explorer and your CUR don't match (2026)

    Same dataset, three different totals. The six differences AWS documents between billing data, Cost Explorer and the Cost and Usage Report, which number you actually owe, and what Cost Explorer charges per API request and per hourly usage record.

  • When moving S3 data to a cheaper storage class costs more (2026)

    Every S3 class below Standard carries a minimum storage duration, a minimum billable object size, a retrieval fee, or all three. The 128 KB rounding rule, the 40 KB Glacier metadata overhead billed partly at Standard rate, and where Intelligent-Tiering avoids both.