A note on this story: Numbers below are from a composite of 14 RDS Postgres audits (cluster sizes db.t3.medium up to db.r6i.16xlarge, monthly RDS spend $2K–$120K).
If you run Postgres on AWS RDS at any meaningful scale, you've had this thought:
"Can our RDS bill really be $40K/month? Just for 3 databases?"
Yes. And it can be half that if you know where to look.
We've audited 14 production Postgres RDS setups in the last year. Median overspend: 53%. Same patterns, every time. Below is the exact playbook we run with customers.
Pattern 1: Wrong instance class (the single biggest waste)
RDS Postgres instance classes are a maze. You can pick from:
- t-class (burstable, cheap, surprise CPU credits)
- m-class (general purpose, balanced)
- r-class (memory optimised, $$$ but worth it for OLAP)
- x-class (extreme memory, $$$$ — almost never the right choice)
Most teams over-provision because RDS sizing is opaque. The default upgrade path goes db.t3 → db.m5 → db.r5 whenever performance hiccups, and nobody downsizes again when the workload shrinks.
The fix:
- Pull last 30 days CloudWatch metrics:
CPUUtilization (max), FreeableMemory (min), DatabaseConnections (max)
- If max CPU < 50% AND min FreeableMemory > 30% of RAM → drop one instance size
- Repeat monthly. Most teams can drop 1–2 sizes within 90 days.
Typical savings: 30–50% of compute spend.
Pattern 2: gp2 storage instead of gp3
AWS still defaults to gp2 for new RDS instances. gp3 is 20% cheaper per GB AND lets you provision IOPS independently from storage size.
| Storage | Price | Baseline IOPS | Throughput |
|---|
| gp2 | $0.115/GB | 3 IOPS/GB | scales w/ size |
| gp3 | $0.092/GB | 3,000 IOPS free | 125 MB/s free |
The migration: RDS console → Modify → Storage Type → gp3. Zero downtime. Typical savings: 15–25% of storage cost.
Why doesn't everyone do this? Because the RDS UI nudges you toward gp2 on instance creation. Set a Slack reminder to migrate every quarter.
Pattern 3: Provisioned IOPS you don't use
Provisioned IOPS (io1 / io2) costs $0.10/IOPS/month on top of storage. Many teams provision 10,000 IOPS "just in case" and never come close to using them.
The audit:
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name ReadIOPS \
--dimensions Name=DBInstanceIdentifier,Value=YOUR_DB \
--start-time $(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 3600 --statistics Maximum
If your max ReadIOPS+WriteIOPS is below 60% of provisioned, drop the IOPS allocation by 30%. Repeat until you hit ~70% utilisation.
Typical savings: $300–$2K/month per database.
Pattern 4: No reserved instances on long-running databases
Production databases are always on, always growing, always there. They're the textbook RI use case. Yet >60% of the RDS spend we audit is on-demand.
The math:
- 1-year all-upfront RI: ~30% off on-demand
- 3-year all-upfront RI: ~55% off on-demand
For a database you've been running 5+ years and have no plans to migrate off, a 3-year RI is essentially free money.
The fix:
- Production primaries → 3-year all-upfront
- Production replicas → 1-year no-upfront
- Dev/staging/test → never RI (you'll resize them constantly)
Typical savings: $1K–$10K/month for any company with $20K+ in RDS spend.
Pattern 5: Backup retention default = 7 days. You probably need 14, not 35.
Default RDS backup retention is 7 days. Many teams crank it to 35 "for safety" and forget. Storage of automated backups beyond DB size is $0.095/GB/month.
A 1TB database with 35-day retention = ~$3K/month JUST in backup storage.
The fix:
- Production databases → 14 days operational + monthly snapshots for compliance
- Staging / dev → 1 day max
- Use snapshot lifecycle policies to age old snapshots into S3 Glacier (10x cheaper)
Typical savings: $500–$3K/month per database.
Pattern 6: Read replicas nobody reads from
Pattern: launch → growing concerns about scale → spin up a read replica → forget about it → 18 months later it costs as much as the primary, but the application never uses it.
The audit:
- CloudWatch → RDS → DatabaseConnections — if average <2 connections to the replica, kill it
We've found one company running 5 idle read replicas (~$3K/month) "in case they were needed someday."
Typical savings: $500–$5K/month.
Pattern 7: Multi-AZ on dev/staging
Multi-AZ doubles your RDS cost. It's required for production HA. It's almost never required for dev or staging.
The fix: flip Multi-AZ off for non-prod. RDS console → Modify → Multi-AZ → No. 50% storage + compute reduction on those instances overnight.
Typical savings: $200–$2K/month per dev/staging database.
Pattern 8: Aurora vs RDS — when each is right
Aurora costs ~20% more than equivalent RDS Postgres at the same instance class, but Aurora gives you:
- Auto-scaling storage (no manual provisioning)
- 3x faster failover
- Up to 15 read replicas with sub-millisecond lag
Use Aurora when:
- Workload exceeds 100GB and grows fast (storage auto-scaling pays off)
- You need >2 read replicas (free additional replicas vs $$$ on RDS)
- You need fast failover (Aurora ~30s vs RDS ~3min)
Use RDS Postgres when:
- Workload is small and stable
- You're cost-sensitive and 3-min failover is acceptable
- You need full Postgres extension support (Aurora is missing some)
Switching between them is a one-way snapshot+restore — pick once and stick.
Pattern 9: Performance Insights at $7.30/host/month
Performance Insights is genuinely useful. It's also charged per-instance-per-month and most teams have it on for every dev/staging instance they never look at.
The fix: disable for non-prod. Keep on production. Saves $7.30 × number-of-non-prod-instances/month.
For an org with 20 RDS instances (10 of which are non-prod), that's $73/month — small per line, but easy to audit and never review again.
Pattern 10: Engine version stagnation
AWS regularly improves RDS performance per dollar with each minor release. Postgres 12 → 13 → 14 → 15 → 16 each came with measurable performance improvements. Running 4-year-old Postgres on RDS means paying for compute that newer versions would do for less.
The fix:
- Plan a quarterly minor-version upgrade
- Run pgbench comparisons before and after
- Watch for IO/CPU efficiency gains — typically 5–15% per major version
The 5-minute audit
- Right-size primaries: look at last 30d max CPU + min FreeableMemory. If max CPU <50% AND min memory >30% → drop one size.
- Migrate gp2 → gp3: RDS console → Modify → Storage Type → gp3. Zero downtime, 20% off.
- Cancel idle replicas: look for replicas with <2 avg DatabaseConnections.
- Disable Multi-AZ on dev/staging: halves cost on non-prod overnight.
- Buy 1-yr RIs on stable production: 30% off, easy decision for long-running workloads.
Steps 1–4 alone usually cut RDS bills 30%.
How CARTIEAI helps
CARTIEAI's RDS optimizer connects to your AWS account, runs all 10 patterns automatically, and gives you a per-database savings report. Typical first-scan: $4K–$15K/month projected savings.
Even without a tool, the 5-minute audit will find $1K–$3K/month of waste in any setup with $5K+ in RDS spend.
Now go check your storage type. 🥃