Snowflake Idle Warehouse Cost: Find the Credits You're Burning
Your Snowflake bill may be paying for warehouses that run nothing. Here is the SQL to measure idle credits per warehouse, fix auto-suspend and stop it coming back.
Snowflake idle warehouse cost is the credits a warehouse bills while it is running but executing no queries. You can measure it by subtracting query-attributed credits from total compute credits in SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY, grouped by warehouse. The fix is usually a lower AUTO_SUSPEND value, separate warehouses for separate workloads, and a resource monitor so it cannot creep back.
A pattern we see repeatedly in growth-stage companies is a Snowflake bill that climbs while query volume stays flat. Nobody wrote a bad query. A scheduler wakes a warehouse, the job finishes in a couple of minutes, and the warehouse then sits billing until the suspend timer fires. This post shows you how to measure that in about five minutes, how to fix it without breaking dashboards, and how to catch it in CI so it does not return.
Why Does Snowflake Bill for Time Nothing Is Running?
A virtual warehouse bills for every second it is up, not for every second it is working. Billing is per second of active runtime, with a 60-second minimum charge on every warehouse start. After the last query finishes, the warehouse stays awake until AUTO_SUSPEND expires. The default is 600 seconds (10 minutes).
Here is the arithmetic that makes this expensive. A Medium warehouse burns 4 credits an hour, because each size step doubles the rate. Say a dbt job wakes it every hour:
10-minute tail: 4 credits/hr x (10/60) = 0.67 credits idle per run
x 24 runs/day = ~16 credits/day of pure idle
60-second tail: 4 x (1/60) x 24 = ~1.6 credits/day
That is roughly 14 credits a day, or about 430 credits a month, from one setting on one warehouse. At an illustrative $3 per credit (your contract rate will differ) that is around $1,300 a month, and it multiplies with every warehouse you have.
Scale makes it worse. A 2026 analysis from cloud-cost vendor PointFive argues that at scale, a 34% idle rate can translate to over $1M per year in wasted compute credits. Treat that as an indication from a vendor with a product to sell, not a benchmark. The mechanism is real, though. Most teams set up warehouses once and never revisit the timer.

📺 Watch: STOP wasting money in Snowflake! | Cost optimization
Which Workloads Cause Idle Warehouse Credits?
In our work with early-stage companies, three causes account for most of it:
- Scheduler bursts. Airflow or dbt Cloud fires at the top of the hour, runs briefly, then leaves a 10-minute tail. Multiply by every schedule you have.
- BI tools polling. A dashboard with a frequent auto-refresh keeps a warehouse awake all day for a handful of seconds of real work. We replaced a 90-minute manual weekly report with a live dashboard that updates hourly. That was the right call, but only after checking that the warehouse behind it was sized and suspended properly.
- Shared warehouses. Loading, transformation, BI and ad-hoc analysis all share one warehouse, so it never gets a quiet period to suspend, and nobody can say which workload is responsible.
A related symptom is a warehouse with AUTO_SUSPEND set to NULL or 0, which means it never suspends. One forgotten value there is the fastest way to a surprise invoice.
How Do You Find Snowflake Idle Warehouse Cost in Five Minutes?
You need a role with access to the SNOWFLAKE database, usually ACCOUNTADMIN or a role granted the right imported privileges. Run these three queries in order.
Query 1: idle credits and idle percentage per warehouse (last 30 days)
SELECT
warehouse_name,
ROUND(SUM(credits_used_compute), 2) AS compute_credits,
ROUND(SUM(credits_attributed_compute_queries), 2) AS query_credits,
ROUND(SUM(credits_used_compute)
- SUM(credits_attributed_compute_queries), 2) AS idle_credits,
ROUND(100 * (SUM(credits_used_compute)
- SUM(credits_attributed_compute_queries))
/ NULLIF(SUM(credits_used_compute), 0), 1) AS idle_pct
FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY
WHERE start_time >= DATEADD('day', -30, CURRENT_TIMESTAMP())
AND start_time < DATEADD('hour', -6, CURRENT_TIMESTAMP())
GROUP BY warehouse_name
ORDER BY idle_credits DESC;
This works because warehouse idle time is not included in the CREDITS_ATTRIBUTED_COMPUTE_QUERIES column, so the difference is your idle spend. The six-hour cut-off matters. The view can lag by up to 180 minutes, and the attributed-credits column can lag longer, so the newest hours look artificially idle if you include them. Also note that CREDITS_ATTRIBUTED_COMPUTE_QUERIES is NULL for Adaptive Warehouses, so those will not show meaningful numbers here.
Query 2: warehouses whose config is the problem
SHOW WAREHOUSES;
SELECT "name", "size", "auto_suspend", "auto_resume",
"min_cluster_count", "max_cluster_count"
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
WHERE "auto_suspend" IS NULL
OR "auto_suspend" = 0
OR "auto_suspend" > 300
ORDER BY "auto_suspend" DESC NULLS FIRST;
Anything that appears here is a candidate. Cross-reference it with Query 1: a warehouse with a long timer and a high idle percentage is your first fix.
Query 3: hours where a warehouse billed but attributed no query credits
SELECT warehouse_name, start_time, credits_used_compute
FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY
WHERE start_time >= DATEADD('day', -7, CURRENT_TIMESTAMP())
AND start_time < DATEADD('hour', -6, CURRENT_TIMESTAMP())
AND credits_used_compute > 0
AND COALESCE(credits_attributed_compute_queries, 0) = 0
ORDER BY credits_used_compute DESC
LIMIT 50;
This surfaces whole hours of billing with nothing to show for it, typically a warehouse left awake overnight or a tool holding a connection open. Run it, then check who or what touched that warehouse just before those hours in QUERY_HISTORY.
Idle time lives in account usage data, so it needs queries like these. Running them for one warehouse is fine. Checking every model in a dbt project for the code-side causes is not. fintel-scan is a free, open-source (MIT) CLI that runs a set of static checks on a dbt project locally, with no warehouse connection: uvx fintel-scan. If you would rather have a team do the whole audit, explore our services.
How Do You Reduce Snowflake Idle Warehouse Cost Without Breaking Dashboards?
Do not set every warehouse to 60 seconds blindly. Warehouses cache data on local SSD, and suspending clears it. Setting auto-suspend aggressively low can cost you more, because the local cache is cleared on suspend. Use workload shape as your decision framework:
- Scheduled ELT and dbt runs: 60 seconds. The warehouse is supposed to be off between runs, and the cache rarely helps.
- BI dashboards with bursty viewers: 120 to 300 seconds. Test it, and watch query time after the change.
- Repeated queries over the same tables: keep a longer timer only if you can show cache hits are saving real time.
- Ad-hoc analyst work: 60 to 120 seconds. People are slower than jobs, and a cold start is a few seconds.
Then apply the change per warehouse:
ALTER WAREHOUSE transform_wh SET AUTO_SUSPEND = 60 AUTO_RESUME = TRUE;
ALTER WAREHOUSE bi_wh SET AUTO_SUSPEND = 180 AUTO_RESUME = TRUE;
Keep AUTO_RESUME on, or the first dashboard query after suspension will fail to run. Next, split mixed workloads. If transformation, loading and BI share one warehouse, give each its own so the transformation warehouse can suspend between runs while BI keeps its own rhythm. Splitting also makes attribution simple: the credits in Query 1 now map to a team or a job.
If the credits in Query 1 are going to a few specific dbt jobs, tag them so you can prove it. Set a query tag per dbt run. We cover the same idea for BigQuery in dbt Query Labels in BigQuery: Fix Your Cost Attribution, and the principle carries over to Snowflake query tags.
Finally, measure. Re-run Query 1 after a week and compare idle_credits per warehouse with the baseline you saved before changing anything. A tuned timer on a scheduled-ELT warehouse typically removes most of its idle line. Check performance too, since cache effects show up as slower first queries, not as errors.

How Do You Stop Idle Warehouse Credits Coming Back?
Optimisations regress. Someone raises a timer to debug a latency problem and forgets to put it back. A new BI tool gets pointed at the transformation warehouse. Put guardrails in code.
1. A resource monitor per warehouse group. It caps the damage if something goes wrong:
CREATE OR REPLACE RESOURCE MONITOR rm_transform
WITH CREDIT_QUOTA = 200
FREQUENCY = MONTHLY
START_TIMESTAMP = IMMEDIATELY
TRIGGERS ON 75 PERCENT DO NOTIFY
ON 100 PERCENT DO SUSPEND;
ALTER WAREHOUSE transform_wh SET RESOURCE_MONITOR = rm_transform;
Creating monitors requires ACCOUNTADMIN. Pick quotas from your measured baseline, not a guess.
2. A dbt model and test over account usage. Materialise idle percentage by warehouse and week, then fail loudly when it drifts. A singular test returns the rows that should not exist:
-- tests/assert_warehouse_idle_pct_under_threshold.sql
{{ config(severity='warn') }}
SELECT warehouse_name,
SUM(credits_used_compute) AS compute_credits,
100 * (SUM(credits_used_compute)
- SUM(credits_attributed_compute_queries))
/ NULLIF(SUM(credits_used_compute), 0) AS idle_pct
FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY
WHERE start_time >= DATEADD('day', -7, CURRENT_TIMESTAMP())
AND start_time < DATEADD('hour', -6, CURRENT_TIMESTAMP())
GROUP BY warehouse_name
HAVING SUM(credits_used_compute) > 10
AND idle_pct > 40
The threshold of 40% and the 10-credit floor are starting points. Tune them to your workload so the test flags real problems and not tiny warehouses. Run it on a schedule, route the warning to the channel your team already watches, and review it monthly.
3. Review new warehouses. Make "what is the AUTO_SUSPEND and who owns this warehouse?" a required question in any pull request that creates one.
We see the same shape of problem on every warehouse we audit: cloud bills that triple quarter on quarter with no governance in place. Idle time is the cheapest part to fix, because it needs configuration, not rewrites.
Frequently Asked Questions
Q: How do I find idle time in Snowflake?
A: Subtract SUM(credits_attributed_compute_queries) from SUM(credits_used_compute) in SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY, grouped by warehouse_name. The difference is credits billed while the warehouse was up but not executing queries. Exclude the most recent six hours because of view latency.
Q: What is the default auto-suspend in Snowflake?
A: The default AUTO_SUSPEND is 600 seconds, or 10 minutes. Every warehouse bills idle time for that long after its last query unless you lower it. Many teams never revisit it after initial setup.
Q: Is a 60-second auto-suspend always the best setting?
A: No. It is a sensible default for scheduled ELT and dbt warehouses, but BI and repeated-query workloads can benefit from a warm cache. Each resume also costs a 60-second minimum, so a warehouse that suspends and resumes every minute can cost more than one left running slightly longer.
Q: Does QUERY_ATTRIBUTION_HISTORY include idle cost?
A: No. Snowflake documents that the credits in that view cover query execution only and exclude warehouse idle time. To allocate idle cost to teams, combine it with WAREHOUSE_METERING_HISTORY and spread the remainder proportionally.
Q: How do I stop a runaway Snowflake warehouse?
A: Attach a resource monitor with a credit quota and a SUSPEND trigger, and set a sensible AUTO_SUSPEND value. Add a scheduled check on idle percentage so drift gets flagged early. Resource monitors cap spend, but they do not fix the underlying configuration.
Conclusion
Snowflake idle warehouse cost is rarely a single dramatic mistake. It is a default timer, a shared warehouse and a scheduler nobody has revisited, all quietly billing between queries. At Fintel Analytics, we have helped fast-growing fintech and e-commerce teams audit warehouse spend, split workloads, and put dbt tests and monitors around cost so savings stay saved. If your Snowflake bill is growing faster than your usage, that is a fixable problem, and a short data strategy consultation will show you where the credits are actually going.
