# RDS Instance Right-sizing

> Downsizing an RDS instance is recommended when 30-day CPU averages under the 10% threshold. ZopNight guards on FreeableMemory (abstains below a 512 MiB minimum) and on connection load near 80% of the target class's ceiling, pricing savings as the compute-rate delta times 730 hours times measured uptime, because storage never shrinks.

Source: https://zop.dev/integrations/aws/recommendations/rds-instance-right-sizing
Updated: 2026-08-19

---

## The memory, idle, and connection guards

- resource.Status: statusAvailable
- MetricsAware: rdsCPUMetricName over rdsMetricLookbackDays days
- Memory guard (D3, 2026-06-26 production audit): now reads the native FreeableMemory metric (bytes), not the never-populated freeable_memory_pct tag (which made the old guard inert). Fail-closed: when the series is present and its full-window Minimum is below rdsFreeableMemoryFloorBytes (512 MiB) the DB is memory-constrained → abstain. RDS [exposes free memory but not total](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/monitoring-cloudwatch.html), so the recommender uses this absolute floor (a future total-memory signal would let it gate on %-free). DatabaseConnections feeds the description and two guards: an idle-DB guard (window peak == 0 with the series present => abstain; an unused DB is a stop/decommission candidate, not a downsize) and a connection-limit guard (abstain when avg or peak ≥ 80% of the target class's RAM-derived default max_connections ceiling, PostgreSQL/MySQL/MariaDB only; fails open for unmapped classes/engines or an absent series).

## The CPU threshold and lookback window

```text
rdsCPUThresholdPercent=10.0, rdsMetricLookbackDays=30, rdsFreeableMemoryFloorBytes=512 MiB
```

## Why only the compute rate delta counts

the original math (RealDeltaSavings → fullCost × (1 − dst/src)) multiplied the compute-rate fraction by the full cost incl. allocated storage/backup/IOPS, [line items billed independently of instance class](https://aws.amazon.com/rds/pricing/) and so unchanged by a tier downsize, overstating savings ~50–65% (audit finding). Savings is now the compute-rate delta scaled by measured uptime: (srcRate − dstRate) × 730 × uptime (uptime via UptimeForUID, fail-open to 24×7 when unknown, matching CommitmentBreakEven's hourlyRate × 730 × uptime basis). A first cut that used (src−dst) × 730 without the uptime factor was a v1.28.1 regression: on part-time test DBs (sit2/uat/pp) whose currentCost is already uptime-discounted, the 24×7 delta overstated and even capped at full cost; caught on the 2026-06-26 fleet re-verify. The result is upper-bounded at cost × (1 − dst/src) (compute can't exceed the resource's own spend; also guards an anomalous SKU-rate delta and is never larger than the legacy ratio) and abstains on uptime 0 / missing rates / non-reduction. Never a fraction of full cost.
PricingAware: compute-only rate delta savings = (srcRate − dstRate) × 730 × measured uptime (fail-open to 24×7 when uptime unknown), capped at cost × (1 − dst/src); abstains on missing/non-reducing SKU rates, no nameable target class, or savings ≤ 0 (rdsDownsizeSavingsFraction = 0.50 is a retained legacy const, no longer multiplied)

## Downsizing during a maintenance window

1. Review 30-day CloudWatch CPU, FreeableMemory, and connections metrics
2. Check RDS Performance Insights for query patterns
3. Modify instance → change to smaller class (e.g., db.m5.xlarge → db.m5.large)
4. Apply during maintenance window
5. Monitor performance for 48 hours after change

## CPU, freeable memory, and connections

CPUUtilization + FreeableMemory + DatabaseConnections (all in RequiredMetrics; rdsMetricLookbackDays lookback)
