Skip to main content

RDS Instance Multi-AZ Deployment

Overview

This check verifies whether your Amazon RDS database instances have Multi-AZ (Multi-Availability Zone) deployment enabled. Multi-AZ automatically maintains a synchronized standby replica of your database in a different Availability Zone, providing automatic failover if something goes wrong with the primary instance.

Risk

Without Multi-AZ protection, your database is vulnerable to single points of failure:

  • Extended downtime: If the Availability Zone hosting your database experiences an outage, your database becomes unavailable until the zone recovers or you manually restore from a backup.
  • Data loss: You may lose transactions that occurred since your last backup.
  • SLA violations: Unplanned downtime can breach service-level agreements with your customers.
  • Manual recovery burden: You would need to restore from backups, which is time-consuming and error-prone.

Remediation Steps

Prerequisites

You need permission to modify RDS instances (typically via the rds:ModifyDBInstance IAM permission).

Important considerations before enabling Multi-AZ
  • Cost impact: Multi-AZ roughly doubles your RDS instance cost since AWS maintains a standby replica.
  • Brief I/O pause: Enabling Multi-AZ on an existing instance may cause a brief I/O freeze (typically a few seconds) during the transition.
  • Storage requirement: Ensure you have adequate storage provisioned, as both instances use the same storage allocation.
  • Not supported for all instance types: Some older or smaller instance types may not support Multi-AZ.

AWS Console Method

  1. Open the Amazon RDS console.
  2. In the left navigation, click Databases.
  3. Select the database instance you want to modify.
  4. Click the Modify button.
  5. Scroll down to the Availability & durability section.
  6. Select Create a standby instance (recommended for production usage).
  7. Scroll to the bottom and click Continue.
  8. Under Schedule modifications, choose:
    • Apply immediately if you want the change now (may cause brief I/O pause)
    • Apply during the next scheduled maintenance window for less disruption
  9. Click Modify DB instance.
  10. Wait for the instance status to return to Available (this may take several minutes).
AWS CLI (optional)

Enable Multi-AZ on an existing RDS instance:

aws rds modify-db-instance \
--db-instance-identifier <your-db-instance-id> \
--multi-az \
--apply-immediately \
--region us-east-1

Replace <your-db-instance-id> with your actual database instance identifier.

To apply during the next maintenance window instead:

aws rds modify-db-instance \
--db-instance-identifier <your-db-instance-id> \
--multi-az \
--no-apply-immediately \
--region us-east-1

Check the modification status:

aws rds describe-db-instances \
--db-instance-identifier <your-db-instance-id> \
--query 'DBInstances[0].{Status:DBInstanceStatus,MultiAZ:MultiAZ,PendingModifiedValues:PendingModifiedValues}' \
--region us-east-1
CloudFormation (optional)

Set MultiAZ: true in your AWS::RDS::DBInstance resource:

AWSTemplateFormatVersion: '2010-09-09'
Description: RDS instance with Multi-AZ enabled

Parameters:
DBInstanceIdentifier:
Type: String
Description: Unique identifier for the RDS instance
DBInstanceClass:
Type: String
Default: db.t3.medium
Description: Instance class for the RDS instance
Engine:
Type: String
Default: mysql
AllowedValues:
- mysql
- postgres
- mariadb
- oracle-ee
- sqlserver-ee
Description: Database engine
MasterUsername:
Type: String
Description: Master username for the database
AllocatedStorage:
Type: Number
Default: 20
Description: Allocated storage in GB
VPCSecurityGroupIds:
Type: List<AWS::EC2::SecurityGroup::Id>
Description: Security groups for the RDS instance
DBSubnetGroupName:
Type: String
Description: DB subnet group name

Resources:
RDSInstance:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceIdentifier: !Ref DBInstanceIdentifier
DBInstanceClass: !Ref DBInstanceClass
Engine: !Ref Engine
MasterUsername: !Ref MasterUsername
ManageMasterUserPassword: true
AllocatedStorage: !Ref AllocatedStorage
MultiAZ: true
VPCSecurityGroups: !Ref VPCSecurityGroupIds
DBSubnetGroupName: !Ref DBSubnetGroupName
StorageEncrypted: true
PubliclyAccessible: false

Outputs:
DBInstanceEndpoint:
Description: RDS instance endpoint
Value: !GetAtt RDSInstance.Endpoint.Address

Note: This template uses ManageMasterUserPassword: true to let AWS Secrets Manager handle the password securely.

Terraform (optional)

Set multi_az = true in your aws_db_instance resource:

terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = "us-east-1"
}

variable "db_instance_identifier" {
description = "Unique identifier for the RDS instance"
type = string
}

variable "db_instance_class" {
description = "Instance class for the RDS instance"
type = string
default = "db.t3.medium"
}

variable "engine" {
description = "Database engine"
type = string
default = "mysql"
}

variable "engine_version" {
description = "Database engine version"
type = string
default = "8.0"
}

variable "allocated_storage" {
description = "Allocated storage in GB"
type = number
default = 20
}

variable "db_name" {
description = "Name of the database"
type = string
}

variable "username" {
description = "Master username"
type = string
}

variable "password" {
description = "Master password"
type = string
sensitive = true
}

variable "vpc_security_group_ids" {
description = "List of VPC security group IDs"
type = list(string)
}

variable "db_subnet_group_name" {
description = "DB subnet group name"
type = string
}

resource "aws_db_instance" "main" {
identifier = var.db_instance_identifier
instance_class = var.db_instance_class
engine = var.engine
engine_version = var.engine_version
allocated_storage = var.allocated_storage
db_name = var.db_name
username = var.username
password = var.password

# Enable Multi-AZ for high availability
multi_az = true

vpc_security_group_ids = var.vpc_security_group_ids
db_subnet_group_name = var.db_subnet_group_name

storage_encrypted = true
publicly_accessible = false
skip_final_snapshot = false
final_snapshot_identifier = "${var.db_instance_identifier}-final-snapshot"

tags = {
Name = var.db_instance_identifier
}
}

output "db_instance_endpoint" {
description = "RDS instance endpoint"
value = aws_db_instance.main.endpoint
}

output "db_instance_arn" {
description = "RDS instance ARN"
value = aws_db_instance.main.arn
}

To enable Multi-AZ on an existing instance, simply add or change:

multi_az = true

Then run:

terraform plan
terraform apply

Verification

After enabling Multi-AZ, verify it is active:

  1. In the RDS console, go to Databases.
  2. Select your database instance.
  3. In the Configuration tab, look for Multi-AZ - it should show Yes.
CLI verification
aws rds describe-db-instances \
--db-instance-identifier <your-db-instance-id> \
--query 'DBInstances[0].MultiAZ' \
--region us-east-1

This should return true.

To list all instances without Multi-AZ:

aws rds describe-db-instances \
--query 'DBInstances[?MultiAZ==`false`].DBInstanceIdentifier' \
--region us-east-1

Additional Resources

Notes

  • Aurora clusters: Amazon Aurora uses a different architecture with built-in replication. Aurora DB clusters inherently provide high availability, but individual Aurora instances still benefit from Multi-AZ placement.
  • Read replicas vs. Multi-AZ: Read replicas are for scaling read traffic; Multi-AZ is for high availability. They serve different purposes and can be used together.
  • Failover testing: Consider periodically testing failover using the aws rds reboot-db-instance --force-failover command to ensure your application handles failover gracefully.
  • Connection handling: Ensure your application uses the RDS endpoint (not IP addresses) and implements proper connection retry logic to handle transparent failover.