Reserved Capacity for Databases
Key concepts
RDS Reserved Instances
ElastiCache Reserved Nodes
DynamoDB Reserved Capacity
Term commitments
Payment options
Overview
AWS offers Reserved pricing models for its managed database services, providing significant discounts (up to 77%) in exchange for upfront commitments of 1 or 3 years. Understanding how to leverage reserved capacity across RDS, ElastiCache, and DynamoDB is crucial for cost optimization and is a frequent topic on the SAA-C03 exam.
Core Concept
Database Reserved Capacity works differently across services: RDS Reserved Instances commit to specific instance types and database engines with size flexibility, ElastiCache Reserved Nodes commit to exact node types with no flexibility, and DynamoDB Reserved Capacity commits to provisioned read/write capacity units. All three share common pricing models with 1-year or 3-year terms and three payment options (All Upfront, Partial Upfront, No Upfront), with discounts increasing for longer terms and more upfront payment.
The exam frequently tests your ability to choose the right reserved pricing strategy based on workload predictability, term flexibility needs, and cost optimization goals. Remember: Reserved capacity provides the best ROI for stable, predictable database workloads. Always analyze 30+ days of usage data before committing, and reserve for baseline capacity (70-80%) rather than peak usage.
Key Concepts
RDS Reserved Instances

RDS Reserved Instance Fundamentals
Definition: RDS Reserved Instances (RIs) provide a discount (up to 72%) compared to On-Demand pricing in exchange for a 1-year or 3-year commitment to a specific database instance configuration.
Commitment Parameters:
- DB Instance Class: Specific instance type (e.g., db.m5.large, db.r5.xlarge)
- Database Engine: MySQL, PostgreSQL, MariaDB, Oracle, SQL Server, Aurora
- License Model: License Included or Bring Your Own License (BYOL)
- Region: Reservation applies to a specific AWS Region
- Deployment Type: Single-AZ or Multi-AZ
Key Characteristics:
- Discount applies automatically to matching instances
- Cannot be moved between regions
- Can be modified within the same instance family (size flexibility for supported engines)
- Multi-AZ reservations cost approximately 2x Single-AZ
- Does NOT provide capacity guarantee (unlike EC2 Zonal RIs)
- Can be shared across accounts in AWS Organizations
RDS RI Size Flexibility
Purpose: Apply a single reserved instance across multiple smaller instances or a larger instance within the same family
Supported Engines (size flexibility enabled):
- Aurora (MySQL and PostgreSQL)
- MySQL
- PostgreSQL
- MariaDB
- Oracle BYOL
NOT Supported (must match exactly):
- Oracle License Included
- SQL Server (all editions)
How It Works:
- RDS RIs use a normalization factor based on instance size
- Reservation applies across any size within the same instance family and region
- Automatically distributes discount across eligible instances
Normalization Factors (db.r5 family example): | Instance Size | Normalization Factor | |---------------|---------------------| | db.r5.large | 1 | | db.r5.xlarge | 2 | | db.r5.2xlarge | 4 | | db.r5.4xlarge | 8 | | db.r5.8xlarge | 16 | | db.r5.12xlarge | 24 | | db.r5.16xlarge | 32 | | db.r5.24xlarge | 48 |
Example: One db.r5.2xlarge RI (factor 4) can cover:
- 1x db.r5.2xlarge, OR
- 2x db.r5.xlarge, OR
- 4x db.r5.large, OR
- 1x db.r5.xlarge + 2x db.r5.large
RDS RI Discount Levels
Typical Discount Ranges (varies by instance type and engine):
| Term | Payment Option | Discount vs On-Demand | |------|----------------|----------------------| | 1 Year | No Upfront | ~18-31% | | 1 Year | Partial Upfront | ~31-37% | | 1 Year | All Upfront | ~33-42% | | 3 Year | No Upfront | ~40-44% | | 3 Year | Partial Upfront | ~58-64% | | 3 Year | All Upfront | ~60-72% |
Factors Affecting Discount:
- Instance family (newer families may have different discounts)
- Database engine (Oracle and SQL Server typically have different pricing)
- Region (pricing varies by region)
- Deployment type (Single-AZ vs Multi-AZ)
Multi-AZ Considerations:
- Multi-AZ RIs cost ~2x Single-AZ RIs
- Multi-AZ discount percentages are similar to Single-AZ
- Reserve Multi-AZ if running Multi-AZ deployments
- For size-flexible engines, Multi-AZ RIs can flex within Multi-AZ deployments
ElastiCache Reserved Nodes

ElastiCache Reserved Node Fundamentals
Definition: ElastiCache Reserved Nodes provide significant discounts (up to 55%) for Redis or Memcached clusters in exchange for a 1-year or 3-year commitment.
Commitment Parameters:
- Cache Node Type: Specific node type (e.g., cache.m5.large, cache.r5.xlarge)
- Cache Engine: Redis or Memcached
- Region: Reservation applies to a specific AWS Region
- Node Count: Number of nodes to reserve
Key Characteristics:
- Applies to matching nodes in any cluster within the region
- Does NOT support size flexibility (unlike RDS)
- Cannot be modified after purchase
- Must match engine type exactly
- Applies to both primary and replica nodes
- Applies automatically to matching On-Demand nodes
ElastiCache Reserved Node Discounts
Typical Discount Ranges:
| Term | Payment Option | Discount vs On-Demand | |------|----------------|----------------------| | 1 Year | No Upfront | ~25-30% | | 1 Year | Partial Upfront | ~38-42% | | 1 Year | All Upfront | ~40-45% | | 3 Year | No Upfront | N/A (not available) | | 3 Year | Partial Upfront | ~50-53% | | 3 Year | All Upfront | ~53-55% |
Important Notes:
- 3-Year No Upfront is NOT available for ElastiCache
- Redis and Memcached have similar discount structures
- Reserved nodes apply automatically to matching on-demand nodes
- Must reserve nodes for BOTH primary and replica nodes
Cluster Mode Considerations (Redis):
- Cluster mode enabled: Reserve nodes for all shards and replicas
- Cluster mode disabled: Reserve primary + replica nodes
- Plan total node count carefully before purchasing
ElastiCache Reserved Node Planning
Strategy: Analyze cluster configuration and reserve for stable node count
Planning Steps:
- Document all ElastiCache clusters and their configurations
- Identify node types and counts (primary + replicas per cluster)
- Analyze usage patterns - is node count stable?
- Reserve for minimum consistent node configuration
- Use On-Demand for scaling headroom or planned growth
Example Calculation:
- Redis cluster: 3 shards, 2 replicas per shard
- Total nodes: 3 (primary) + 6 (replica) = 9 nodes
- If using cache.r5.large across all nodes
- Reserve: 9x cache.r5.large reserved nodes
Reserved Node Application:
- ElastiCache automatically applies reservations
- Matches by region, engine, and node type (exact match)
- No action needed after purchase
- Reservations shared across accounts if enabled in Organizations
DynamoDB Reserved Capacity

DynamoDB Reserved Capacity Fundamentals
Definition: DynamoDB Reserved Capacity provides significant discounts (up to 77%) on provisioned throughput capacity in exchange for a 1-year or 3-year commitment.
Commitment Parameters:
- Read Capacity Units (RCUs): Minimum 100 RCUs per reservation
- Write Capacity Units (WCUs): Minimum 100 WCUs per reservation
- Region: Reservation applies to a specific AWS Region
Key Characteristics:
- Applies ONLY to Provisioned capacity mode (NOT On-Demand)
- Purchased separately for RCUs and WCUs
- Can purchase multiple reservations to increase coverage
- Applies automatically to provisioned capacity usage in region
- Does NOT apply to Global Secondary Index (GSI) capacity automatically
- No size flexibility - use-it-or-lose-it model
Important Limitations:
- Minimum purchase: 100 RCUs or 100 WCUs per reservation
- Cannot apply to On-Demand (PAY_PER_REQUEST) tables
- Cannot transfer between regions
- GSI capacity must be considered separately
- Does not cover storage costs
DynamoDB Reserved Capacity Discounts
Discount Levels (approximate):
| Term | Payment Option | Discount vs Provisioned On-Demand | |------|----------------|----------------------------------| | 1 Year | No Upfront | ~25% | | 1 Year | Partial Upfront | ~42% | | 1 Year | All Upfront | ~54% | | 3 Year | No Upfront | ~53% | | 3 Year | Partial Upfront | ~75% | | 3 Year | All Upfront | ~77% |
Cost Comparison Example (1000 WCUs, us-east-1):
- Provisioned On-Demand: ~$470/month
- 1-Year All Upfront Reserved: ~$216/month effective
- 3-Year All Upfront Reserved: ~$108/month effective
GSI Considerations:
- GSI capacity is billed separately from base table
- Reserved capacity covers total provisioned capacity in region
- Applies across all tables and GSIs using provisioned mode
- Plan total regional capacity needs including GSIs
DynamoDB Reserved Capacity Strategy
Hybrid Approach: Combine reserved capacity with auto-scaling
Planning Steps:
- Analyze 30+ days of CloudWatch metrics for all tables
- Sum baseline (minimum consistent) capacity across tables/GSIs
- Reserve 70-80% of total baseline capacity
- Configure auto-scaling for capacity above reserved
- Review quarterly and adjust reservations
Example Architecture:
- Table 1: 300 WCUs baseline, peaks to 800
- Table 2: 200 WCUs baseline, peaks to 500
- Total baseline: 500 WCUs
- Reserved: 400 WCUs (80% of baseline)
- Auto-scaling handles peaks up to combined 1500 WCUs
When NOT to Use Reserved Capacity:
- Unpredictable or highly variable workloads
- New applications without usage history
- Tables using On-Demand capacity mode
- Short-term or temporary tables
- Workloads being migrated to serverless
Term Commitments: 1-Year vs 3-Year

1-Year Term Analysis
Characteristics:
- Lower commitment risk
- Easier to adapt to changing needs
- Lower discount than 3-year (typically 15-25% less savings)
- Annual review opportunity to adjust
Best For:
- Growing or evolving workloads
- New applications (after initial 30+ day usage analysis)
- Organizations uncertain about long-term needs
- First-time reserved capacity users
- Workloads with potential technology changes
Discount Range Comparison: | Service | 1-Year All Upfront | 3-Year All Upfront | |---------|-------------------|-------------------| | RDS (open-source) | 33-42% | 60-72% | | RDS (commercial) | 27-37% | 40-60% | | ElastiCache | 40-45% | 53-55% | | DynamoDB | ~54% | ~77% |
3-Year Term Analysis
Characteristics:
- Maximum discount potential
- Higher commitment risk
- Significant savings for stable workloads
- Less flexibility for changes
Best For:
- Production workloads with 3+ years projected lifespan
- Stable, predictable capacity requirements
- Organizations with strong forecasting capabilities
- Cost optimization as primary goal
- Workloads with low likelihood of technology change
Risk Considerations:
- Technology changes may make instance types obsolete
- Business needs may change significantly
- No ability to modify, cancel, or sell
- Unused capacity is fully paid regardless of utilization
- Database engine migrations not supported
Payment Options Comparison
Payment Options Comparison
| Payment Option | Upfront Cost | Monthly Cost | Total Discount | Cash Flow Impact | Best For |
|---|---|---|---|---|---|
| All Upfront | 100% at purchase | $0 | Highest (up to 72-77%) | High initial impact | Maximum savings, available capital |
| Partial Upfront | ~50% at purchase | ~50% monthly | Medium (up to 60-75%) | Balanced | Balance of savings and cash flow |
| No Upfront | $0 | 100% monthly | Lowest (up to 40-55%) | Minimal initial impact | Preserve capital, still get meaningful savings |
Choosing Payment Options
All Upfront:
- Requires significant capital outlay
- Maximum discount (up to additional 10-15% over No Upfront)
- Best for: Organizations with available budget prioritizing lowest TCO
- Consider: Opportunity cost of capital
Partial Upfront:
- Balance of discount and cash flow
- Typically ~half the savings between No Upfront and All Upfront
- Best for: Organizations wanting savings without full upfront investment
- Most popular option for large enterprises
No Upfront:
- Minimal initial investment required
- Still provides meaningful discount (25-55% depending on service)
- Best for: Startups, organizations with cash flow constraints
- Lower risk if needs change unexpectedly
Decision Framework:
- Calculate total cost over term for each option
- Compare to available capital and budget cycles
- Consider opportunity cost of upfront payment
- Factor in risk of unused capacity
- Evaluate finance team preferences
Cross-Service Comparison
Database Reserved Capacity Comparison
| Feature | RDS Reserved Instances | ElastiCache Reserved Nodes | DynamoDB Reserved Capacity |
|---|---|---|---|
| Commitment Type | Instance class + engine | Node type + engine | RCUs and WCUs |
| Size Flexibility | Yes (most engines) | No | No |
| Max Discount (3-yr All Upfront) | Up to 72% | Up to 55% | Up to 77% |
| Minimum Purchase | 1 instance | 1 node | 100 RCUs or 100 WCUs |
| Region Locked | Yes | Yes | Yes |
| Can Modify After Purchase | Yes (size within family) | No | No |
| Applies Automatically | Yes | Yes | Yes |
| Cross-Account Sharing | Yes (Organizations) | Yes (Organizations) | Yes (Organizations) |
| Capacity Reservation Guarantee | No | No | No |
# List available RDS reserved instance offerings
aws rds describe-reserved-db-instances-offerings \
--db-instance-class db.r5.large \
--product-description mysql \
--offering-type "All Upfront" \
--query 'ReservedDBInstancesOfferings[*].{OfferingId:ReservedDBInstancesOfferingId,Duration:Duration,Price:FixedPrice,Class:DBInstanceClass}'
# Filter by term length (31536000 = 1 year, 94608000 = 3 years)
aws rds describe-reserved-db-instances-offerings \
--db-instance-class db.r5.large \
--duration 94608000 \
--product-description aurora-mysql
# Purchase RDS reserved instance
aws rds purchase-reserved-db-instances-offering \
--reserved-db-instances-offering-id <offering-id> \
--reserved-db-instance-id my-aurora-reservation \
--db-instance-count 2
# List current RDS reserved instances
aws rds describe-reserved-db-instances \
--query 'ReservedDBInstances[*].{Id:ReservedDBInstanceId,Class:DBInstanceClass,State:State,Start:StartTime,End:StartTime}'# List available ElastiCache reserved node offerings
aws elasticache describe-reserved-cache-nodes-offerings \
--cache-node-type cache.r5.large \
--product-description redis \
--offering-type "All Upfront" \
--query 'ReservedCacheNodesOfferings[*].{OfferingId:ReservedCacheNodesOfferingId,Duration:Duration,Price:FixedPrice}'
# List all offerings for a specific node type
aws elasticache describe-reserved-cache-nodes-offerings \
--cache-node-type cache.m5.large
# Purchase ElastiCache reserved nodes
aws elasticache purchase-reserved-cache-nodes-offering \
--reserved-cache-nodes-offering-id <offering-id> \
--reserved-cache-node-id my-redis-reservation \
--cache-node-count 6
# List current ElastiCache reserved nodes
aws elasticache describe-reserved-cache-nodes \
--query 'ReservedCacheNodes[*].{Id:ReservedCacheNodeId,NodeType:CacheNodeType,State:State,Count:CacheNodeCount}'# List available DynamoDB reserved capacity offerings
aws dynamodb describe-reserved-capacity-offerings \
--query 'ReservedCapacityOfferings[*].{OfferingId:ReservedCapacityOfferingId,Duration:Duration,Type:OfferingType}'
# Purchase DynamoDB reserved capacity
aws dynamodb purchase-reserved-capacity-offerings \
--reserved-capacity-offering-id <offering-id> \
--capacity-specification ReadCapacityUnits=500,WriteCapacityUnits=200
# List current DynamoDB reserved capacity
aws dynamodb describe-reserved-capacity \
--query 'ReservedCapacity[*].{Id:ReservedCapacityId,State:State}'# Get reserved instance utilization report
aws ce get-reservation-utilization \
--time-period Start=2024-01-01,End=2024-01-31 \
--filter '{"Dimensions":{"Key":"SERVICE","Values":["Amazon Relational Database Service"]}}' \
--granularity MONTHLY
# Get reserved instance coverage report
aws ce get-reservation-coverage \
--time-period Start=2024-01-01,End=2024-01-31 \
--filter '{"Dimensions":{"Key":"SERVICE","Values":["Amazon Relational Database Service"]}}' \
--granularity MONTHLY
# Get reservation purchase recommendations for RDS
aws ce get-reservation-purchase-recommendation \
--service "Amazon Relational Database Service" \
--lookback-period-in-days SIXTY_DAYS \
--term-in-years ONE_YEAR \
--payment-option ALL_UPFRONT
# Get reservation recommendations for ElastiCache
aws ce get-reservation-purchase-recommendation \
--service "Amazon ElastiCache" \
--lookback-period-in-days SIXTY_DAYS \
--term-in-years THREE_YEARS \
--payment-option PARTIAL_UPFRONT
# Get reservation recommendations for DynamoDB
aws ce get-reservation-purchase-recommendation \
--service "Amazon DynamoDB" \
--lookback-period-in-days THIRTY_DAYSBest Practices
- Analyze Before Committing: Review at least 30-60 days of usage data before purchasing reserved capacity
- Start Conservative: Reserve 70-80% of baseline capacity, not peak usage
- Monitor Utilization: Regularly check reservation utilization in Cost Explorer to identify waste
- Use Size Flexibility (RDS): Purchase larger RDS RIs that can flex across smaller instances
- Plan for Multi-AZ (RDS): If running Multi-AZ, purchase Multi-AZ reservations
- Reserve All Nodes (ElastiCache): Include both primary and replica nodes in reservations
- Combine with Auto-Scaling: Use reserved capacity for baseline, auto-scaling for peaks
- Review Quarterly: Adjust reserved capacity strategy based on changing usage patterns
- Enable Cross-Account Sharing: In AWS Organizations, share reservations to maximize utilization
- Consider 1-Year First: Start with 1-year terms until workloads prove stable over time
Common Exam Scenarios
Exam Scenario Decision Guide
| Scenario | Recommended Solution | Key Reasoning |
|---|
Common Pitfalls
Reserving for Peak Instead of Baseline
Reserving capacity for peak usage rather than baseline wastes money. Reserved capacity is use-it-or-lose-it - if you reserve 1000 WCUs but consistently use only 500 WCUs, you pay for 1000 WCUs. Always reserve for your minimum consistent baseline (typically 70-80% of average), and use auto-scaling or On-Demand for peaks.
Forgetting ElastiCache Has No Size Flexibility
Unlike RDS Reserved Instances, ElastiCache Reserved Nodes do NOT support size flexibility. If you reserve cache.r5.large nodes but later need cache.r5.xlarge, your reservations won't apply to the new nodes. Plan ElastiCache node types carefully and consider whether scaling up is likely before purchasing long-term reservations.
Ignoring Multi-AZ Configuration for RDS
RDS Multi-AZ deployments effectively run two instances (primary + standby). A Single-AZ reservation covers only Single-AZ deployments. If you're running Multi-AZ but purchased Single-AZ reservations, the reservation won't apply correctly. Always match your reservation deployment type to your actual deployment configuration.
Reserving DynamoDB Capacity for On-Demand Tables
DynamoDB Reserved Capacity ONLY applies to tables in Provisioned capacity mode. If your tables use On-Demand (PAY_PER_REQUEST) billing mode, reserved capacity provides zero benefit and goes completely unused. Before purchasing DynamoDB reserved capacity, verify your tables use Provisioned mode with stable capacity requirements.
Not Accounting for All ElastiCache Nodes
ElastiCache Reserved Nodes must cover ALL nodes in your clusters - both primary and replica nodes. A 3-shard Redis cluster with 2 replicas per shard has 9 total nodes. Reserving only 3 nodes (primaries) leaves 6 nodes (replicas) on expensive On-Demand pricing. Calculate total node count across all clusters before purchasing.
Related Services
Quick Reference
Reserved Capacity Comparison
| Feature | RDS RI | ElastiCache RN | DynamoDB RC |
|---|---|---|---|
| Max Discount | 72% | 55% | 77% |
| Size Flexibility | Yes (most engines) | No | No |
| Minimum Purchase | 1 instance | 1 node | 100 RCU/WCU |
| Can Modify | Yes (size within family) | No | No |
| Terms Available | 1-yr, 3-yr | 1-yr, 3-yr | 1-yr, 3-yr |
| 3-Year No Upfront | Yes | No | Yes |
Payment Option Discounts (Approximate)
| Payment Option | 1-Year Discount | 3-Year Discount |
|---|---|---|
| All Upfront | 33-54% | 55-77% |
| Partial Upfront | 31-42% | 50-75% |
| No Upfront | 18-30% | 40-53% |
Key CLI Commands
# RDS - List reserved instance offerings
aws rds describe-reserved-db-instances-offerings \
--db-instance-class db.r5.large \
--product-description mysql
# RDS - List current reservations
aws rds describe-reserved-db-instances
# ElastiCache - List reserved node offerings
aws elasticache describe-reserved-cache-nodes-offerings \
--cache-node-type cache.r5.large
# ElastiCache - List current reservations
aws elasticache describe-reserved-cache-nodes
# DynamoDB - List reserved capacity offerings
aws dynamodb describe-reserved-capacity-offerings
# Cost Explorer - Get reservation recommendations
aws ce get-reservation-purchase-recommendation \
--service "Amazon Relational Database Service" \
--lookback-period-in-days SIXTY_DAYS \
--term-in-years ONE_YEAR \
--payment-option ALL_UPFRONT
# Cost Explorer - Check reservation utilization
aws ce get-reservation-utilization \
--time-period Start=2024-01-01,End=2024-01-31 \
--granularity MONTHLY
Decision Framework
| Question | If Yes | If No |
|---|---|---|
| Stable workload for 1+ years? | Consider Reserved | Use On-Demand |
| Can analyze 30+ days of usage? | Calculate optimal reservation | Wait for data |
| Instance type likely to change? | Use RDS size-flex or shorter term | Full reservation OK |
| Cash flow constrained? | No Upfront option | All Upfront for max savings |
| Running Multi-AZ (RDS)? | Purchase Multi-AZ RI | Single-AZ RI OK |
| Using DynamoDB On-Demand mode? | Reserved won't apply | Switch to Provisioned first |
| ElastiCache nodes may scale? | 1-Year term, re-evaluate | 3-Year term OK |
Test Your Knowledge
A company runs a production MySQL database on RDS using db.r5.xlarge in a Multi-AZ deployment. The database has been stable for 2 years and is expected to run for at least 3 more years. They want to maximize cost savings. What is the MOST cost-effective reserved instance purchase?
A company uses DynamoDB with Provisioned capacity mode. Their table consistently uses 800 WCUs with occasional peaks to 2000 WCUs during sales events. They want to optimize costs while handling peaks. What is the BEST strategy?
A company has an ElastiCache Redis cluster with 3 shards and 2 replicas per shard (9 nodes total) using cache.m5.large. The cluster has been stable for 18 months. What should they reserve to maximize savings?
A company purchased RDS Reserved Instances for db.r5.2xlarge (MySQL) but now needs to run four db.r5.large instances instead. What happens to their reservation?