Skip to main content

Overview

This guide covers Multi-AZ RDS clusters, which use the standard mysql or postgres engine — not the Aurora engines (aurora-mysql or aurora-postgresql). The configuration, instance types, and storage model differ significantly from Aurora clusters.
A Multi-AZ DB cluster (distinct from a Multi-AZ DB instance) is a semi-synchronous high-availability deployment that places a writer and two readable standby instances across three separate Availability Zones. Unlike Aurora, this mode uses local storage attached to each instance, making allocated_storage, iops, and storage_type required configuration. This module supports Multi-AZ RDS clusters using the same terraform-aws-modules/rds-aurora/aws source. The key difference is how the module detects which mode you want:
Setting allocated_storage to a non-null value is what switches the module into Multi-AZ RDS cluster mode. When allocated_storage is set, the module assigns cluster_instance_class to the db_cluster_instance_class attribute of the underlying aws_rds_cluster resource. Without allocated_storage, instances are managed separately as Aurora cluster instances. See the upstream discussion for details on why this proxy is used.

Supported Engines

EngineValue
PostgreSQLpostgres
MySQLmysql
Do not use aurora-postgresql or aurora-mysql — those are Aurora engines and incompatible with Multi-AZ DB cluster storage settings.

Working Example

The following is taken directly from examples/multi-az/. It provisions a PostgreSQL Multi-AZ RDS cluster with provisioned IOPS storage, Performance Insights, and automatic password rotation.
provider "aws" {
  region = local.region
}

data "aws_availability_zones" "available" {
  # Exclude local zones
  filter {
    name   = "opt-in-status"
    values = ["opt-in-not-required"]
  }
}

locals {
  name   = "ex-multi-az"
  region = "eu-west-1"

  vpc_cidr = "10.0.0.0/16"
  azs      = slice(data.aws_availability_zones.available.names, 0, 3)

  tags = {
    Example    = local.name
    GithubRepo = "terraform-aws-rds-aurora"
    GithubOrg  = "terraform-aws-modules"
  }
}

module "aurora" {
  source = "terraform-aws-modules/rds-aurora/aws"

  name            = local.name
  engine          = "postgres" # This uses RDS engine, not Aurora
  engine_version  = "17.5"
  master_username = "root"

  vpc_id               = module.vpc.vpc_id
  db_subnet_group_name = module.vpc.database_subnet_group_name

  manage_master_user_password_rotation                   = true
  master_user_password_rotation_automatically_after_days = 30

  enabled_cloudwatch_logs_exports = ["postgresql"]

  cluster_performance_insights_enabled          = true
  cluster_performance_insights_retention_period = 31

  # Multi-AZ
  availability_zones     = module.vpc.azs
  allocated_storage      = 256
  cluster_instance_class = "db.c6gd.large"
  iops                   = 2500
  storage_type           = "io1"

  cluster_ca_cert_identifier = "rds-ca-rsa4096-g1"

  skip_final_snapshot = true

  tags = local.tags
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 6.0"

  name = local.name
  cidr = local.vpc_cidr

  azs              = local.azs
  public_subnets   = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)]
  private_subnets  = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 3)]
  database_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 6)]

  tags = local.tags
}

Key Configuration Details

Storage

Multi-AZ RDS clusters require explicit storage configuration. The example uses provisioned IOPS (io1) for predictable performance:
allocated_storage      = 256   # GiB per instance
storage_type           = "io1" # Required for Multi-AZ
iops                   = 2500  # Provisioned IOPS
io1 is the required storage_type for Multi-AZ DB clusters. Aurora clusters use aurora or aurora-iopt1 instead.

Instance Class

Multi-AZ DB clusters use different instance families than Aurora. In the example, db.c6gd.large is used — this class has local NVMe SSD storage and is optimized for I/O-intensive workloads:
cluster_instance_class = "db.c6gd.large"
Note that cluster_instance_class here maps to db_cluster_instance_class on the aws_rds_cluster resource (not to individual aws_rds_cluster_instance resources, which are not created for Multi-AZ RDS clusters).

Availability Zones

Pass all three AZs explicitly so the cluster places instances predictably:
availability_zones = module.vpc.azs
If fewer than 3 AZs are specified, RDS will auto-assign them — but this can cause a diff on subsequent Terraform plans.

CA Certificate

The cluster_ca_cert_identifier variable specifies which Certificate Authority the cluster’s TLS certificate should be signed by:
cluster_ca_cert_identifier = "rds-ca-rsa4096-g1"
This is currently only supported for Multi-AZ DB clusters (not Aurora). Choose a CA that matches your client TLS requirements and certificate rotation schedule.

Variable Reference

VariableTypeDefaultDescription
enginestringnullUse mysql or postgres (not Aurora variants)
allocated_storagenumbernullStorage in GiB per instance — required to enable Multi-AZ mode
cluster_instance_classstringnullInstance class for Multi-AZ DB instances (e.g. db.c6gd.large)
storage_typestringnullUse io1 for Multi-AZ clusters
iopsnumbernullProvisioned IOPS for io1 storage
availability_zoneslist(string)nullList of 3 AZs to place instances in
cluster_ca_cert_identifierstringnullCA certificate identifier (Multi-AZ only)

Build docs developers (and LLMs) love