Skip to main content
INS // Insights

Aurora Serverless v2 Cost Optimization Guide

Updated July 2026 · 4 min read

Aurora Serverless v2 promises to scale capacity to match load automatically, but the default configuration many teams deploy with — a conservative minimum ACU floor "just to be safe" — quietly defeats much of the cost benefit that made serverless attractive in the first place.

How Aurora Serverless v2 Billing Actually Works

Aurora Serverless v2 bills based on Aurora Capacity Units (ACUs) consumed per second, scaling between a configured minimum and maximum. Unlike v1's scaling granularity, v2 scales in fine-grained increments and can respond to load changes within seconds — which is genuinely useful for variable workloads, but only if the minimum floor is actually set low enough to capture savings during low-traffic periods.

The Minimum ACU Trap

A common pattern we see: a team migrates to Aurora Serverless v2, sets the minimum ACU to match roughly what their previous provisioned instance's baseline load required "to be safe," and never revisits it. The result is a database that never scales below that floor even during genuinely idle periods (nights, weekends for B2B-pattern traffic), paying for capacity nobody's using.

aws rds modify-db-cluster \
  --db-cluster-identifier my-cluster \
  --serverless-v2-scaling-configuration MinCapacity=0.5,MaxCapacity=8

Dropping the minimum from, say, 2 ACUs to 0.5 ACUs for a workload with genuine idle periods can meaningfully reduce baseline cost — but only if you've verified the workload can actually tolerate scaling that low without unacceptable latency during the scale-up transition when traffic returns.

Understanding Scaling Latency Before You Set an Aggressive Minimum

The tradeoff for a low minimum is scale-up latency — moving from a very low ACU floor back up to handle a traffic spike takes some time, even though Aurora Serverless v2 scales faster than v1 did. For workloads with genuinely unpredictable, sudden traffic spikes (not gradual ramps), too aggressive a minimum can produce a real, measurable latency penalty during the scale-up window. Test this directly rather than assuming — simulate a cold-to-spike transition in a staging environment and measure actual query latency during the scaling event.

Right-Sizing the Maximum, Not Just the Minimum

Teams focused on the minimum-ACU cost lever sometimes leave the maximum set far higher than the workload has ever actually needed, as a hedge against unexpected traffic. This doesn't cost anything extra unless the workload actually scales up to use it — but it's worth periodically checking CloudWatch's ServerlessDatabaseCapacity metric against your actual peak usage to confirm the ceiling still makes sense, since an outdated max set for a previous, since-resolved traffic pattern (a since-fixed inefficient query, a migrated-away legacy integration) may no longer be necessary.

Read Replica Scaling Considerations

For read-heavy workloads using Aurora Serverless v2 read replicas, each replica scales its own ACU independently based on its own load — meaning a read replica serving a reporting workload with predictable low-traffic overnight periods can have its own tighter minimum than the writer instance, if traffic patterns actually differ between them.

Monitoring What Actually Drives Cost

def analyze_acu_utilization(cluster_id: str, days: int = 14) -> dict:
    cw = boto3.client("cloudwatch")
    response = cw.get_metric_statistics(
        Namespace="AWS/RDS",
        MetricName="ServerlessDatabaseCapacity",
        Dimensions=[{"Name": "DBClusterIdentifier", "Value": cluster_id}],
        StartTime=datetime.utcnow() - timedelta(days=days),
        EndTime=datetime.utcnow(),
        Period=3600,
        Statistics=["Average", "Maximum"],
    )
    datapoints = response["Datapoints"]
    return {
        "avg_acu": sum(d["Average"] for d in datapoints) / len(datapoints),
        "p95_acu": sorted(d["Maximum"] for d in datapoints)[int(len(datapoints) * 0.95)],
        "min_observed": min(d["Average"] for d in datapoints),
    }

Pulling a couple weeks of actual ACU utilization data — not a single day, since weekly and even monthly patterns matter — gives you the real data to set both minimum and maximum intentionally rather than guessing.

Frequently Asked Questions

How low can the minimum ACU realistically go for a production workload?

Aurora Serverless v2 supports a minimum as low as 0.5 ACU, but "realistic" depends entirely on your workload's tolerance for scale-up latency during traffic transitions — test this directly rather than assuming the lowest technically-allowed value is always the right choice.

Does Aurora Serverless v2 cost more than a comparably-sized provisioned instance at steady, predictable load?

For a workload with genuinely flat, predictable 24/7 load with no meaningful variation, a provisioned instance is often more cost-effective, since Serverless v2's flexibility premium isn't offset by any actual scaling benefit. Serverless v2's advantage is specifically for variable-load workloads.

How often should ACU scaling configuration be revisited?

Whenever your traffic pattern changes meaningfully (a new feature driving different usage, a since-fixed inefficient query that was inflating baseline load), or at minimum a periodic quarterly review against actual CloudWatch utilization data.

Can Aurora Serverless v2 scale to zero when completely idle?

No — the minimum is 0.5 ACU, so there's always some baseline cost even during genuinely zero-traffic periods, unlike some serverless compute models that can scale fully to zero.

Does this optimization approach apply to both Aurora MySQL and PostgreSQL compatible editions?

Yes, the ACU scaling configuration and cost optimization approach apply identically across both engine compatibility modes, since the underlying Aurora Serverless v2 capacity model is engine-agnostic.


See what a 2-week AWS cost audit finds in your account → rutagon.com/contact or call 907-841-8407.