Managed Postgres Cost: Aurora, Cloud SQL, and Azure
Managed Postgres bills inflate through oversized instances, wasted IOPS, redundant replicas, and excessive backup retention. Here's how to cut 30-50%.
By Andrii Votiakov on
Every major cloud sells you managed Postgres — Aurora PostgreSQL, Cloud SQL, Azure Database for PostgreSQL. The underlying database is the same. The billing models are different, and so are the waste patterns. But the core problems are nearly identical: instances sized for peak loads that happened once, IOPS provisioned out of caution, replicas that nobody reads from, and backup retention nobody ever thought to revisit.
Quick answer
Managed Postgres bills typically carry 30-50% waste. Right-sizing instances is the largest lever (15-25% alone). Fixing IOPS over-provisioning, read replica utilisation, and backup retention adds another 15-25%. After that, reserved capacity or committed use discounts on the right-sized floor lock in another 25-35%.
Instance right-sizing: the same method regardless of cloud
Pull 14 days of CPU, memory, and connection metrics — not a week, not a day. You want enough data to capture weekly patterns and see whether peak is an event or a steady state.
What I look for:
- CPU below 20% average, peaks under 60% — you're probably one instance class too large
- Active connections well below
max_connections— memory is being wasted holding a connection pool you don't need - Buffer cache hit rate above 99.5% with headroom to spare — your working set fits in significantly less RAM than you're paying for
On Aurora PostgreSQL, pg_stat_activity and pg_stat_statements give you the operational picture. On Cloud SQL, the Query Insights panel does the same work. Azure Database for PostgreSQL has Intelligent Performance with similar data.
Don't trust single-day screenshots. Pull the data, look at the shape of the curve.
Aurora PostgreSQL: the specific levers
Aurora has a few billing dimensions that vanilla RDS and other managed services don't:
Storage I/O costs: Standard Aurora bills separately for storage I/O at $0.20 per million requests. If your I/O bill is above 25% of total monthly Aurora spend, switch to Aurora I/O-Optimised — one parameter change, no downtime. I/O-Optimised bundles I/O into the storage rate at $0.225/GB-month, and saves money once I/O intensity crosses the threshold.
Aurora Serverless v2: scales from 0.5 ACUs to a defined maximum. Good for dev, staging, or low-traffic production databases where the load pattern is genuinely spiky. Watch the maximum ACU setting — leave it unbounded and a bad query can run up hundreds of dollars in an hour. Always set an explicit cap.
Read replicas: each costs the same as a writer instance per hour. Audit whether your application routes reads to replicas at all. I regularly find clusters with two or three replicas added "for HA" that receive near-zero read traffic. Each one is costing $200-800/month.
Backtrack window: billed per GB-hour of change data retained. If you don't use it operationally, set it to 0.
Cloud SQL: IOPS and the flex tier
Cloud SQL for PostgreSQL charges for vCPUs, memory, and storage separately. The storage default is HDD-backed, but SSD is the right choice for most databases — the performance difference is large and the price premium is modest.
The expensive mistake on Cloud SQL is over-provisioning IOPS on SSD. Cloud SQL lets you provision custom IOPS on top of the baseline. These are billed per provisioned IOPS, not used. If you provisioned 10,000 IOPS because of a performance incident six months ago and actual utilisation sits at 2,000, you're paying for 8,000 IOPS you don't use.
Cloud SQL also has an Enterprise Plus tier (newer) with higher performance and better pricing for sustained production workloads. If you're still on the older Enterprise tier with a large instance, the recalculation is worth doing.
Read replica pricing on Cloud SQL follows the same logic as the primary: you pay full instance cost for every replica. Same audit applies — are they being read from? Check pg_stat_activity on each replica during your peak traffic window.
Azure Database for PostgreSQL: the Flexible Server migration
If you're still on Azure Database for PostgreSQL Single Server — stop. It was deprecated in 2025. The replacement is Flexible Server, which is cheaper for the same compute class and adds more tuning options.
Flexible Server pricing is also more transparent about compute vs. storage vs. IOPS. Provisioned IOPS above the baseline incur charges — same pattern as Cloud SQL. Check your provisioned vs. actual IOPS ratio.
Azure's Business Critical tier is noticeably more expensive than General Purpose for the same vCore count. Business Critical adds locally redundant storage in NVMe. If you're running on Business Critical for a staging or non-critical production workload, downgrade to General Purpose and save 30-40% on the compute line.
When self-hosted Postgres on EC2 or GCE makes sense
Self-hosted on EC2 or GCE means you manage backups, failover, patching, and replication. That's real operational cost. But it also means:
- No managed service premium (Aurora charges roughly 20% more per compute hour than equivalent EC2)
- Full control over storage: gp3 on EC2 with explicit IOPS provisioning is often 30-40% cheaper than equivalent Aurora storage
- RI pricing on EC2 applies cleanly, no Aurora-specific RI management
Self-hosted makes sense when: your team has a DBA or has run Postgres for years, the database isn't on a growth path that demands managed autoscaling, and the managed service bill is above ~$3,000/month (below that, the ops time rarely pays back). Tools like Patroni, pgBackRest, and PgBouncer are mature. The setup takes a week, not a month.
I've helped clients move high-volume, stable Postgres workloads from Aurora to EC2-hosted Patroni clusters and cut the database bill by 40-50%. Not the right move for everyone — but worth the calculation.
Backup retention: the policy nobody revisits
Every managed Postgres service charges for backup storage. The default retention is usually 7-35 days of automated backups. Teams set it to the maximum on day one and never look at it again.
Ask yourself: what's your realistic recovery scenario? If your last point-in-time recovery need was "we need to get to yesterday morning," you need 2 days of backups, not 35. If compliance requires 30-day retention, fine — but document that requirement rather than running at the maximum by default.
On a client running Aurora with 35-day retention across 12 databases, dropping to 14 days reduced backup storage costs by $1,100/month. Same actual risk tolerance, less waste.
Realistic numbers
Recent client managing Postgres across AWS and GCP (~$18,500/month combined):
- Aurora instance right-sizing (8 instances): $3,600/month
- Aurora I/O-Optimised switch (2 clusters): $1,400/month
- Cloud SQL IOPS over-provisioning fixed: $1,100/month
- Read replica audit (removed 4 unused replicas across both clouds): $2,200/month
- Backup retention policies corrected: $800/month
- 1-year reserved/committed-use on new floor: $2,700/month
Total: $11,800/month saved, ~64%. Implementation over four weeks, mostly configuration changes and one replica topology change.
If you're also running MongoDB Atlas alongside Postgres, the same waste patterns appear there too — see MongoDB Atlas cost optimisation for the Atlas-specific levers.
If you want me to run the same analysis on your managed Postgres spend on a pay-for-savings basis, book a call.