RDS Storage Full: Enabling Autoscaling Without Downtime (Limits, Triggers & CLI Guide)
An RDS instance approaching its storage ceiling is a production incident waiting to happen — writes fail, connections drop, and recovery under pressure is painful. Understanding how RDS Storage Autoscaling works before you hit the wall is the difference between a non-event and an outage.
TL;DR
| Question | Answer |
|---|---|
| Can I enable autoscaling on a running instance? | ✅ Yes — zero downtime, no reboot required |
| When does autoscaling trigger? | Free storage < 10% of allocated AND < 64 GiB AND low for 5+ minutes |
| How much does it scale per event? | Max of: 5 GiB, 10% of current storage, or 7 hours of projected growth |
| Is there a hard ceiling? | ✅ Yes — you set a Maximum Storage Threshold (up to 65,536 GiB) |
| Does scaling cause downtime? | ❌ No — storage expansion is online for gp2, gp3, io1, io2 |
| Cost impact? | You pay for the expanded storage at the standard EBS rate for your volume type |
How RDS Storage Autoscaling Works Internally
RDS Storage Autoscaling is not a cron job or a Lambda trigger you manage — it is a native RDS control-plane feature that monitors your instance's free storage via CloudWatch and issues an ModifyDBInstance call on your behalf when the trigger conditions are met.
The Three-Condition Trigger (ALL must be true simultaneously)
- Condition 1 — Percentage: Free storage is less than 10% of the currently allocated storage.
- Condition 2 — Absolute floor: Free storage is less than 64 GiB (prevents unnecessary scaling on very large volumes).
- Condition 3 — Duration: Both conditions above have been true for at least 5 consecutive minutes.
Think of it like a car's fuel warning light: it only activates when you're both below a percentage threshold and have been driving on low for long enough to confirm it's not a sensor blip.
Scale Increment Calculation
When triggered, RDS calculates the new target storage as the maximum of these three values:
- Current allocated storage + 5 GiB
- Current allocated storage + 10% of current allocated storage
- Current allocated storage + storage used in the last 7 hours (projected growth rate)
The result is then capped at your configured Maximum Storage Threshold. This prevents runaway scaling from a data import spike while still accommodating organic growth.
Cooldown Period
After a scaling event completes, there is a mandatory 6-hour cooldown before another autoscaling event can trigger. This is enforced by the RDS control plane — you cannot override it.
Architecture: Autoscaling Data Flow
Enabling Autoscaling: CLI-First Approach
Enable on an Existing Instance
Use modify-db-instance with the --max-allocated-storage flag. Setting this flag is what activates autoscaling — the value is your hard ceiling in GiB.
aws rds modify-db-instance \
--db-instance-identifier my-production-db \
--max-allocated-storage 1000 \
--apply-immediately
Note: --apply-immediately applies the configuration change (enabling autoscaling) immediately. The storage expansion itself happens asynchronously when triggered — it does not cause downtime.
Verify the Configuration
aws rds describe-db-instances \
--db-instance-identifier my-production-db \
--query 'DBInstances[0].{Allocated:AllocatedStorage,MaxAllocated:MaxAllocatedStorage,Status:DBInstanceStatus}'
A non-null MaxAllocatedStorage value confirms autoscaling is active.
Terraform Configuration
resource "aws_db_instance" "production" {
identifier = "my-production-db"
allocated_storage = 100
max_allocated_storage = 1000 # Enables autoscaling; set to 0 to disable
engine = "mysql"
instance_class = "db.t3.large"
# ... other config
}
CloudFormation
MyDBInstance:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceIdentifier: my-production-db
AllocatedStorage: 100
MaxAllocatedStorage: 1000
DBInstanceClass: db.t3.large
Engine: mysql
IAM: Minimum Required Permissions
The IAM principal enabling autoscaling needs only these actions — nothing broader:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"rds:ModifyDBInstance",
"rds:DescribeDBInstances"
],
"Resource": "arn:aws:rds:us-east-1:123456789012:db:my-production-db"
}
]
}
The RDS service itself uses a service-linked role (AWSServiceRoleForRDS) to perform the actual ModifyDBInstance call internally — you do not need to grant this to your application role.
Hard Limits and Constraints
| Constraint | Detail |
|---|---|
| Maximum storage ceiling | 65,536 GiB (64 TiB) for most engines |
| Minimum threshold setting | Must be greater than current AllocatedStorage |
| Supported volume types | gp2, gp3, io1, io2 — not magnetic (standard) |
| Supported engines | MySQL, PostgreSQL, MariaDB, Oracle, SQL Server |
| Aurora | Aurora manages storage automatically — this feature does not apply |
| Cooldown between events | 6 hours (hard, non-configurable) |
| Scaling direction | Scale-up only — RDS storage cannot be reduced after expansion |
Cost Impact
- You pay for what is allocated, not what is used. Once autoscaling expands storage from 100 GiB to 200 GiB, your bill reflects 200 GiB even if only 110 GiB is consumed.
- For gp3, storage costs ~$0.115/GiB-month (us-east-1). An expansion from 100 GiB to 200 GiB adds ~$11.50/month.
- For io1/io2, storage is more expensive (~$0.125/GiB-month) and provisioned IOPS are billed separately — autoscaling does not adjust IOPS.
- Set a conservative Maximum Storage Threshold to cap your worst-case storage bill. Treat it as a budget guardrail, not just a technical limit.
Proactive Monitoring: Don't Rely on Autoscaling Alone
Autoscaling is a safety net, not a substitute for observability. Set a CloudWatch alarm to alert you before autoscaling triggers:
aws cloudwatch put-metric-alarm \
--alarm-name rds-storage-warning \
--metric-name FreeStorageSpace \
--namespace AWS/RDS \
--dimensions Name=DBInstanceIdentifier,Value=my-production-db \
--statistic Average \
--period 300 \
--threshold 10737418240 \
--comparison-operator LessThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:123456789012:ops-alerts \
--unit Bytes
The threshold above is 10 GiB in bytes (10 × 1024³). Adjust based on your allocated storage and growth rate.
Glossary
- MaxAllocatedStorage: The RDS parameter that both enables autoscaling and defines the hard upper ceiling for automatic storage expansion.
- FreeStorageSpace: The CloudWatch metric (in bytes) representing unused storage on the RDS EBS volume; the primary signal for autoscaling decisions.
- ModifyDBInstance: The RDS API action used to change instance configuration, including storage size; issued by the control plane during autoscaling events.
- Service-Linked Role (AWSServiceRoleForRDS): An IAM role pre-created by AWS that grants the RDS service permission to call EC2/EBS APIs on your behalf for operations like storage expansion.
- Cooldown Period: The mandatory 6-hour window after a storage autoscaling event during which no further autoscaling can occur, preventing rapid successive expansions.
Comments
Post a Comment