RDS DB clusters should be configured for multiple Availability Zones
A single-AZ database deployment creates an availability bottleneck. If that AZ experiences an outage, your database can become unreachable until failover or recovery actions complete.
Multi-AZ architectures maintain capacity in more than one AZ and support automatic failover. Failover timing varies by engine, topology, and workload, and is typically measured in tens of seconds to a few minutes. The cost difference is real, typically doubling compute spend for equivalent instance counts, but that's usually still less than the business impact of an unplanned outage on a production database.
Retrofit consideration
Implementation
Choose the approach that matches how you manage Terraform.
Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.
This control is enforced automatically with Compliance.tf modules. Start free trial
If you use terraform-aws-modules/rds-aurora/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.
module "rds_aurora" {
source = "terraform-aws-modules/rds-aurora/aws"
version = ">=10.0.0,<11.0.0"
create_db_subnet_group = true
create_security_group = true
engine = "aurora-mysql"
engine_version = "8.0.mysql_aurora.3.08.0"
instances = {
one = {
instance_class = "db.t4g.medium"
}
}
manage_master_user_password = true
master_username = "root"
name = "abc123"
skip_final_snapshot = true
subnets = ["subnet-12345678", "subnet-12345678"]
vpc_id = "vpc-12345678"
}Use AWS provider resources directly. See docs for the resources involved: aws_rds_cluster.
resource "aws_rds_cluster" "this" {
backtrack_window = 72
cluster_identifier = "pofix-abc123"
db_subnet_group_name = "example-db-subnet-group"
enabled_cloudwatch_logs_exports = ["audit"]
engine = "aurora-mysql"
engine_version = "8.0.mysql_aurora.3.08.0"
manage_master_user_password = true
master_username = "dbadmin"
skip_final_snapshot = true
vpc_security_group_ids = ["sg-12345678"]
}What this control checks
For Aurora clusters, the control validates that aws_rds_cluster has availability_zones set to at least two distinct AZs, and that corresponding aws_rds_cluster_instance resources exist in those AZs. Each instance can specify availability_zone to pin it to a particular AZ. A cluster with only one instance, or with all instances in the same AZ, fails. For non-Aurora Multi-AZ DB clusters (engine mysql or postgres), aws_rds_cluster should include at least two entries in availability_zones, and the DB cluster MultiAZ field should be true.
Common pitfalls
Aurora availability_zones is informational at creation
Setting availability_zones on aws_rds_cluster tells AWS which AZs are eligible for instances, but it doesn't guarantee instances actually run there. Deploy at least two aws_rds_cluster_instance resources in separate AZs using the availability_zone argument on each instance to achieve true Multi-AZ.
Serverless v1 clusters may not support Multi-AZ the same way
Aurora Serverless v1 (engine_mode = "serverless") doesn't use discrete cluster instances. Its Multi-AZ behavior is managed internally by AWS and may not surface as MultiAZ: true in the API response. Serverless v2 uses cluster instances with class db.serverless, but HA evidence and behavior should still be validated with Aurora-specific signals rather than assuming identical semantics to provisioned Multi-AZ DB clusters.
Terraform plan shows no drift when AZ removed externally
Delete a cluster instance in a second AZ through the console or CLI, and Terraform will catch the missing aws_rds_cluster_instance on the next plan. But if that instance was never managed by Terraform in the first place, there's no drift to detect, and the cluster silently becomes single-AZ.
Cost doubles with Multi-AZ
Each additional cluster instance in a new AZ incurs full compute charges. For Aurora, a db.r6g.xlarge writer plus one reader roughly doubles the hourly cost from approximately $0.58/hr to $1.16/hr in us-east-1. Budget for this before enabling Multi-AZ across all clusters.
Audit evidence
An auditor expects rds-cluster-multi-az-enabled Config rule results showing compliant status for all in-scope clusters. Supporting evidence includes aws rds describe-db-clusters output filtered to show AvailabilityZones with at least two entries, plus engine-appropriate HA indicators: MultiAZ: true for Multi-AZ DB clusters, and instance placement confirming failover-capable topology for Aurora. Console screenshots of the RDS cluster detail page work as supplementary proof when they show the relevant HA fields for that engine.
For continuous assurance, a compliance dashboard pulling from AWS Config or a CSPM tool should show historical evaluation results confirming Multi-AZ remained enabled throughout the audit period, with no gaps in compliance status.
Framework-specific interpretation
NIST Cybersecurity Framework v2.0: PR.IR (Infrastructure Resilience) and RC.RP (Recovery Planning) are both in scope. PR.IR expects components to remain available during failures, which multi-AZ deployment addresses directly. RC.RP is satisfied by automatic failover: recovery happens without a manual restore operation, which is what that planning requirement is really asking for.
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
- Compliance.tf Control:
rds_db_cluster_multiple_az_enabled - AWS Config Managed Rule:
RDS_CLUSTER_MULTI_AZ_ENABLED - Checkov Check:
CKV_AWS_157 - Powerpipe Control:
aws_compliance.control.rds_db_cluster_multiple_az_enabled - Prowler Check:
rds_cluster_multi_az - AWS Security Hub Control:
RDS.15
Last reviewed: 2026-03-09