home / skills / giuseppe-trisciuoglio / developer-kit / aws-cloudformation-rds

This skill helps you design production-ready AWS CloudFormation patterns for RDS databases, including instances, clusters, subnets, parameter groups, and

npx playbooks add skill giuseppe-trisciuoglio/developer-kit --skill aws-cloudformation-rds

Review the files below or copy the command above to add this skill to your agents.

Files (3)
SKILL.md
47.9 KB
---
name: aws-cloudformation-rds
description: Provides AWS CloudFormation patterns for Amazon RDS databases. Use when creating RDS instances (MySQL, PostgreSQL, Aurora), DB clusters, multi-AZ deployments, parameter groups, subnet groups, and implementing template structure with Parameters, Outputs, Mappings, Conditions, and cross-stack references.
category: aws
tags: [aws, cloudformation, rds, database, mysql, postgresql, aurora, mariadb, oracle, infrastructure, iaac]
version: 1.0.0
allowed-tools: Read, Write, Bash
---

# AWS CloudFormation RDS Database

## Overview

Create production-ready Amazon RDS infrastructure using AWS CloudFormation templates. This skill covers RDS instances (MySQL, PostgreSQL, Aurora, MariaDB), DB clusters, multi-AZ deployments, parameter groups, subnet groups, security groups, template structure best practices, parameter patterns, and cross-stack references for modular, reusable infrastructure as code.

## When to Use

Use this skill when:
- Creating new RDS database instances (MySQL, PostgreSQL, Aurora, MariaDB)
- Configuring DB clusters with read replicas
- Setting up multi-AZ deployments for high availability
- Creating DB parameter groups and option groups
- Configuring DB subnet groups for VPC deployment
- Implementing template Parameters with AWS-specific types
- Creating Outputs for cross-stack references
- Organizing templates with Mappings and Conditions
- Designing reusable, modular CloudFormation templates
- Integrating with Secrets Manager for credential management

## Instructions

Follow these steps to create RDS infrastructure with CloudFormation:

1. **Define Database Parameters**: Specify instance type, engine, and credentials
2. **Configure Subnet Group**: Set up VPC subnets for database deployment
3. **Create Parameter Group**: Define database engine-specific settings
4. **Set Up Security Groups**: Configure network access controls
5. **Enable Multi-AZ**: Deploy standby instance for high availability
6. **Configure Backup**: Set retention periods and snapshot schedules
7. **Add Monitoring**: Enable enhanced monitoring and performance insights
8. **Implement Secrets**: Use Secrets Manager for credential rotation

For complete examples, see the [EXAMPLES.md](references/examples.md) file.

## Examples

The following examples demonstrate common RDS patterns:

### Example 1: MySQL RDS Instance

```yaml
DBInstance:
  Type: AWS::RDS::DBInstance
  Properties:
    DBInstanceIdentifier: !Sub "${AWS::StackName}-mysql"
    Engine: mysql
    DBInstanceClass: db.t3.micro
    MasterUsername: !Ref DBUsername
    MasterUserPassword: !Ref DBPassword
    AllocatedStorage: 20
    StorageType: gp3
    VPCSecurityGroups:
      - !Ref DBSecurityGroup
    DBSubnetGroupName: !Ref DBSubnetGroup
```

### Example 2: Aurora Cluster

```yaml
DBCluster:
  Type: AWS::RDS::DBCluster
  Properties:
    DatabaseName: !Ref DBName
    Engine: aurora-mysql
    MasterUsername: !Ref DBUsername
    MasterUserPassword: !Ref DBPassword
    DBClusterParameterGroupName: !Ref DBParameterGroup
    DBSubnetGroupName: !Ref DBSubnetGroup
    VpcSecurityGroupIds:
      - !Ref DBSecurityGroup

DBInstance:
  Type: AWS::RDS::DBInstance
  Properties:
    DBClusterIdentifier: !Ref DBCluster
    DBInstanceClass: db.t3.medium
    Engine: aurora-mysql
```

### Example 3: PostgreSQL with Multi-AZ

```yaml
DBInstance:
  Type: AWS::RDS::DBInstance
  Properties:
    DBInstanceIdentifier: !Sub "${AWS::StackName}-postgres"
    Engine: postgres
    DBInstanceClass: db.t3.medium
    MasterUsername: !Ref DBUsername
    MasterUserPassword: !Ref DBPassword
    AllocatedStorage: 50
    StorageType: gp3
    MultiAZ: true
    DBSubnetGroupName: !Ref DBSubnetGroup
    VpcSecurityGroupIds:
      - !Ref DBSecurityGroup
```

For complete production-ready examples, see [EXAMPLES.md](references/examples.md).

## Quick Start

### Basic MySQL RDS Instance

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Simple MySQL RDS instance with basic configuration

Parameters:
  DBInstanceIdentifier:
    Type: String
    Default: mydatabase
    Description: Database instance identifier

  MasterUsername:
    Type: String
    Default: admin
    Description: Master username

  MasterUserPassword:
    Type: String
    NoEcho: true
    Description: Master user password

  DBInstanceClass:
    Type: String
    Default: db.t3.micro
    AllowedValues:
      - db.t3.micro
      - db.t3.small
      - db.t3.medium

Resources:
  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: Subnet group for RDS
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2

  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: !Ref DBInstanceIdentifier
      DBInstanceClass: !Ref DBInstanceClass
      Engine: mysql
      MasterUsername: !Ref MasterUsername
      MasterUserPassword: !Ref MasterUserPassword
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !Ref DBSecurityGroup
      AllocatedStorage: "20"
      StorageType: gp3
      MultiAZ: false

Outputs:
  DBInstanceEndpoint:
    Description: Database endpoint address
    Value: !GetAtt DBInstance.Endpoint.Address

  DBInstancePort:
    Description: Database port
    Value: !GetAtt DBInstance.Endpoint.Port
```

### Aurora MySQL Cluster

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Aurora MySQL cluster with writer and reader instances

Parameters:
  DBClusterIdentifier:
    Type: String
    Default: my-aurora-cluster
    Description: Cluster identifier

  MasterUsername:
    Type: String
    Default: admin

  MasterUserPassword:
    Type: String
    NoEcho: true

Resources:
  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: Subnet group for Aurora
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2

  DBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: !Ref DBClusterIdentifier
      Engine: aurora-mysql
      MasterUsername: !Ref MasterUsername
      MasterUserPassword: !Ref MasterUserPassword
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !Ref DBSecurityGroup
      DatabaseName: mydb
      EngineMode: provisioned
      Port: 3306

  DBInstanceWriter:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: !Sub ${DBClusterIdentifier}-writer
      DBClusterIdentifier: !Ref DBCluster
      Engine: aurora-mysql
      DBInstanceClass: db.t3.medium

  DBInstanceReader:
    Type: AWS::RDS::DBInstance
    DependsOn: DBInstanceWriter
    Properties:
      DBInstanceIdentifier: !Sub ${DBClusterIdentifier}-reader
      DBClusterIdentifier: !Ref DBCluster
      Engine: aurora-mysql
      DBInstanceClass: db.t3.medium
      PromotionTier: 2

Outputs:
  ClusterEndpoint:
    Description: Writer endpoint
    Value: !GetAtt DBCluster.Endpoint

  ReaderEndpoint:
    Description: Reader endpoint
    Value: !GetAtt DBCluster.ReadEndpoint
```

## Template Structure

### Template Sections Overview

AWS CloudFormation templates are JSON or YAML files with specific sections. Each section serves a purpose in defining your infrastructure.

```yaml
AWSTemplateFormatVersion: 2010-09-09  # Required - template version
Description: Optional description string  # Optional description

# Section order matters for readability but CloudFormation accepts any order
Mappings: {}       # Static configuration tables
Metadata: {}       # Additional information about resources
Parameters: {}     # Input values for customization
Rules: {}          # Parameter validation rules
Conditions: {}     # Conditional resource creation
Transform: {}      # Macro processing (e.g., AWS::Serverless)
Resources: {}      # AWS resources to create (REQUIRED)
Outputs: {}        # Return values after stack creation
```

### Format Version

The `AWSTemplateFormatVersion` identifies the template version. Current version is `2010-09-09`.

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: My RDS Database Template
```

### Description

Add a description to document the template's purpose. Must appear after the format version.

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: >
  This template creates an RDS MySQL instance with:
  - Multi-AZ deployment for high availability
  - Encrypted storage
  - Automated backups
  - Performance Insights enabled
```

### Metadata

Use `Metadata` for additional information about resources or parameters, including AWS::CloudFormation::Interface for parameter grouping.

```yaml
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Database Configuration
        Parameters:
          - DBInstanceIdentifier
          - Engine
          - DBInstanceClass
      - Label:
          default: Credentials
        Parameters:
          - MasterUsername
          - MasterUserPassword
      - Label:
          default: Network
        Parameters:
          - DBSubnetGroupName
          - VPCSecurityGroups
    ParameterLabels:
      DBInstanceIdentifier:
        default: Database Instance ID
      MasterUsername:
        default: Master Username
```

### Resources Section

The `Resources` section is the only required section. It defines AWS resources to provision.

```yaml
Resources:
  # DB Subnet Group (required for VPC deployment)
  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: Subnet group for RDS deployment
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2

  # DB Parameter Group
  DBParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Description: Custom parameter group for MySQL
      Family: mysql8.0
      Parameters:
        max_connections: 200
        innodb_buffer_pool_size: 1073741824

  # DB Instance
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: mydbinstance
      DBInstanceClass: db.t3.micro
      Engine: mysql
      MasterUsername: admin
      MasterUserPassword: !Ref DBPassword
      DBSubnetGroupName: !Ref DBSubnetGroup
      DBParameterGroupName: !Ref DBParameterGroup
```

## Parameters

### Parameter Types

Use AWS-specific parameter types for validation and easier selection in the console.

```yaml
Parameters:
  # DB instance identifier
  DBInstanceIdentifier:
    Type: String
    Description: Database instance identifier

  # AWS-specific parameter types for validation
  DBInstanceClass:
    Type: AWS::RDS::DBInstance::InstanceType
    Description: RDS instance class
    Default: db.t3.micro

  # Engine version from SSM
  EngineVersion:
    Type: AWS::RDS::DBInstance::Version
    Description: Database engine version
    Default: 8.0

  # For existing VPC security groups
  VPCSecurityGroups:
    Type: List<AWS::EC2::SecurityGroup::Id>
    Description: Security groups for RDS instance
```

### AWS::RDS::DBInstance::InstanceType Values

Common RDS instance types:

```yaml
Parameters:
  DBInstanceClass:
    Type: String
    AllowedValues:
      - db.t3.micro
      - db.t3.small
      - db.t3.medium
      - db.t3.large
      - db.t3.xlarge
      - db.t3.2xlarge
      - db.m5.large
      - db.m5.xlarge
      - db.m5.2xlarge
      - db.m5.4xlarge
      - db.r5.large
      - db.r5.xlarge
      - db.r5.2xlarge
```

### Parameter Constraints

Add constraints to validate parameter values.

```yaml
Parameters:
  DBInstanceIdentifier:
    Type: String
    Description: Database instance identifier
    Default: mydatabase
    AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]*$"
    ConstraintDescription: Must begin with a letter; contain only alphanumeric characters
    MinLength: 1
    MaxLength: 63

  MasterUsername:
    Type: String
    Description: Master username
    Default: admin
    AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]*$"
    MinLength: 1
    MaxLength: 16
    NoEcho: true

  MasterUserPassword:
    Type: String
    Description: Master user password
    NoEcho: true
    MinLength: 8
    MaxLength: 41
    AllowedPattern: "[a-zA-Z0-9]*"

  AllocatedStorage:
    Type: Number
    Description: Allocated storage in GB
    Default: 20
    MinValue: 20
    MaxValue: 65536

  DBPort:
    Type: Number
    Description: Database port
    Default: 3306
    MinValue: 1150
    MaxValue: 65535
```

### Engine and Version Parameters

```yaml
Parameters:
  Engine:
    Type: String
    Description: Database engine
    Default: mysql
    AllowedValues:
      - mysql
      - postgres
      - oracle-ee
      - oracle-se2
      - sqlserver-ee
      - sqlserver-se
      - sqlserver-ex
      - sqlserver-web
      - aurora
      - aurora-mysql
      - aurora-postgresql
      - mariadb

  EngineVersion:
    Type: String
    Description: Database engine version
    Default: 8.0.35

  DBFamily:
    Type: String
    Description: Parameter group family
    Default: mysql8.0
    AllowedValues:
      - mysql5.6
      - mysql5.7
      - mysql8.0
      - postgres11
      - postgres12
      - postgres13
      - postgres14
      - postgres15
      - postgres16
      - aurora5.6
      - aurora-mysql5.7
      - aurora-mysql8.0
      - aurora-postgresql11
      - aurora-postgresql14
```

### SSM Parameter Types

Reference Systems Manager parameters for dynamic values.

```yaml
Parameters:
  LatestMySQLVersion:
    Type: AWS::SSM::Parameter::Value<String>
    Description: Latest MySQL version from SSM
    Default: /rds/mysql/latest/version

  LatestPostgreSQLVersion:
    Type: AWS::SSM::Parameter::Value<String>
    Description: Latest PostgreSQL version from SSM
    Default: /rds/postgres/latest/version
```

### NoEcho for Sensitive Data

Use `NoEcho` for passwords and sensitive values to mask them in console output.

```yaml
Parameters:
  MasterUserPassword:
    Type: String
    Description: Master user password
    NoEcho: true
    MinLength: 8
    MaxLength: 41
```

## Mappings

Use `Mappings` for static configuration data based on regions or instance types.

```yaml
Mappings:
  InstanceTypeConfig:
    db.t3.micro:
      CPU: 2
      MemoryGiB: 1
      StorageGB: 20
    db.t3.small:
      CPU: 2
      MemoryGiB: 2
      StorageGB: 20
    db.t3.medium:
      CPU: 2
      MemoryGiB: 4
      StorageGB: 20
    db.m5.large:
      CPU: 2
      MemoryGiB: 8
      StorageGB: 100

  RegionDatabasePort:
    us-east-1:
      MySQL: 3306
      PostgreSQL: 5432
    us-west-2:
      MySQL: 3306
      PostgreSQL: 5432
    eu-west-1:
      MySQL: 3306
      PostgreSQL: 5432

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass: !FindInMap [InstanceTypeConfig, !Ref DBInstanceClass, CPU]
      Engine: mysql
      # ...
```

## Conditions

Use `Conditions` to conditionally create resources based on parameters.

```yaml
Parameters:
  EnableMultiAZ:
    Type: String
    Default: false
    AllowedValues:
      - true
      - false

  EnableEncryption:
    Type: String
    Default: true
    AllowedValues:
      - true
      - false

  Environment:
    Type: String
    Default: development
    AllowedValues:
      - development
      - staging
      - production

Conditions:
  IsMultiAZ: !Equals [!Ref EnableMultiAZ, true]
  IsEncrypted: !Equals [!Ref EnableEncryption, true]
  IsProduction: !Equals [!Ref Environment, production]

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      MultiAZ: !Ref EnableMultiAZ
      StorageEncrypted: !Ref EnableEncryption
      # Production gets automated backups
      BackupRetentionPeriod: !If [IsProduction, 35, 7]
      DeletionProtection: !If [IsProduction, true, false]
```

### Condition Functions

```yaml
Conditions:
  IsDev: !Equals [!Ref Environment, development]
  IsStaging: !Equals [!Ref Environment, staging]
  IsProduction: !Equals [!Ref Environment, production]

  HasLicense: !Not [!Condition IsDev]

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      # Use license-included for production
      LicenseModel: !If [HasLicense, "license-included", "bring-your-own-license"]
      # Production uses provisioned IOPS
      StorageType: !If [IsProduction, "io1", "gp3"]
      Iops: !If [IsProduction, 3000, !Ref AWS::NoValue]
```

## Transform

Use `Transform` for macros like AWS::Serverless for SAM templates.

```yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: Serverless RDS application template

Globals:
  Function:
    Timeout: 30
    Runtime: python3.11

Resources:
  RDSFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: app.handler
      CodeUri: function/
      Policies:
        - RDSFullAccessPolicy:
            DBInstanceIdentifier: !Ref DBInstanceIdentifier
      Environment:
        Variables:
          DB_HOST: !GetAtt DBInstance.Endpoint.Address
          DB_NAME: !Ref DBName
          DB_USER: !Ref MasterUsername
```

## Outputs and Cross-Stack References

### Basic Outputs

```yaml
Outputs:
  DBInstanceId:
    Description: Database Instance ID
    Value: !Ref DBInstance

  DBInstanceEndpoint:
    Description: Database endpoint address
    Value: !GetAtt DBInstance.Endpoint.Address

  DBInstancePort:
    Description: Database port
    Value: !GetAtt DBInstance.Endpoint.Port

  DBInstanceArn:
    Description: Database Instance ARN
    Value: !GetAtt DBInstance.Arn

  DBInstanceClass:
    Description: Database Instance Class
    Value: !Ref DBInstanceClass
```

### Exporting Values for Cross-Stack References

Export values so other stacks can import them.

```yaml
Outputs:
  DBInstanceId:
    Description: Database Instance ID for other stacks
    Value: !Ref DBInstance
    Export:
      Name: !Sub ${AWS::StackName}-DBInstanceId

  DBInstanceEndpoint:
    Description: Database endpoint for application stacks
    Value: !GetAtt DBInstance.Endpoint.Address
    Export:
      Name: !Sub ${AWS::StackName}-DBEndpoint

  DBInstancePort:
    Description: Database port for application stacks
    Value: !GetAtt DBInstance.Endpoint.Port
    Export:
      Name: !Sub ${AWS::StackName}-DBPort

  DBConnectionString:
    Description: Full connection string for applications
    Value: !Sub jdbc:mysql://${DBInstanceEndpoint}:${DBInstancePort}/${DBName}
    Export:
      Name: !Sub ${AWS::StackName}-DBConnectionString
```

### Importing Values in Another Stack

```yaml
Parameters:
  # Import via AWS::RDS::DBInstance::Id for console selection
  DBInstanceId:
    Type: AWS::RDS::DBInstance::Id
    Description: RDS instance ID from database stack

  # Or use Fn::ImportValue for programmatic access
  DBEndpoint:
    Type: String
    Description: Database endpoint address

Resources:
  ApplicationDatabaseConfig:
    Type: AWS::SSM::Parameter
    Properties:
      Name: /app/database/endpoint
      Value: !Ref DBEndpoint
      Type: String
```

### Cross-Stack Reference Pattern

Create a dedicated database stack that exports values:

```yaml
# database-stack.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Database infrastructure stack

Parameters:
  EnvironmentName:
    Type: String
    Default: production

Resources:
  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: !Sub Subnet group for ${EnvironmentName}
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2

  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass.t3.medium: db
      Engine: mysql
      MasterUsername: admin
      MasterUserPassword: !Ref DBPassword
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !Ref DBSecurityGroup
      MultiAZ: true
      StorageEncrypted: true

Outputs:
  DBInstanceId:
    Value: !Ref DBInstance
    Export:
      Name: !Sub ${EnvironmentName}-DBInstanceId

  DBEndpoint:
    Value: !GetAtt DBInstance.Endpoint.Address
    Export:
      Name: !Sub ${EnvironmentName}-DBEndpoint

  DBArn:
    Value: !GetAtt DBInstance.Arn
    Export:
      Name: !Sub ${EnvironmentName}-DBArn

  DBSubnetGroupName:
    Value: !Ref DBSubnetGroup
    Export:
      Name: !Sub ${EnvironmentName}-DBSubnetGroupName
```

Application stack imports these values:

```yaml
# application-stack.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: Application stack that imports from database stack

Parameters:
  DatabaseStackName:
    Type: String
    Description: Name of the database stack
    Default: database-stack

Resources:
  ApplicationConfig:
    Type: AWS::SSM::Parameter
    Properties:
      Name: /app/database/endpoint
      Value: !ImportValue
        Fn::Sub: ${DatabaseStackName}-DBEndpoint
      Type: String

  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.11
      Handler: app.handler
      Environment:
        Variables:
          DB_ENDPOINT: !ImportValue
            Fn::Sub: ${DatabaseStackName}-DBEndpoint
```

## RDS Database Components

### DB Subnet Group

Required for VPC deployment. Must include at least 2 subnets in different AZs.

```yaml
Resources:
  DBSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: Subnet group for RDS instance
      SubnetIds:
        - !Ref PrivateSubnet1
        - !Ref PrivateSubnet2
        - !Ref PrivateSubnet3
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-dbsubnet
```

### DB Parameter Group

Custom parameter groups for database configuration.

```yaml
Resources:
  DBParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Description: Custom parameter group for MySQL 8.0
      Family: mysql8.0
      Parameters:
        # Connection settings
        max_connections: 200
        max_user_connections: 200

        # Memory settings
        innodb_buffer_pool_size: 1073741824
        innodb_buffer_pool_instances: 4

        # Query cache (MySQL 5.7)
        query_cache_type: 1
        query_cache_size: 268435456

        # Timezone
        default_time_zone: "+00:00"

        # Character set
        character_set_server: utf8mb4
        collation_server: utf8mb4_unicode_ci

      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-dbparam
```

### DB Option Group

For database features like Oracle XML or SQL Server features.

```yaml
Resources:
  DBOptionGroup:
    Type: AWS::RDS::DBOptionGroup
    Properties:
      EngineName: oracle-ee
      MajorEngineVersion: "19"
      OptionGroupDescription: Option group for Oracle 19c
      Options:
        - OptionName: OEM
          OptionVersion: "19"
          Port: 5500
          VpcSecurityGroupMemberships:
            - !Ref OEMSecurityGroup
        - OptionName: SSL
          OptionSettings:
            - Name: SQLNET.SSL_VERSION
              Value: "1.2"
```

### DB Instance - MySQL

```yaml
Resources:
  MySQLDBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: mysql-instance
      DBInstanceClass: db.t3.medium
      Engine: mysql
      EngineVersion: "8.0.35"
      MasterUsername: !Ref MasterUsername
      MasterUserPassword: !Ref MasterUserPassword
      AllocatedStorage: "100"
      StorageType: gp3
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !Ref DBSecurityGroup
      DBParameterGroupName: !Ref DBParameterGroup
      StorageEncrypted: true
      MultiAZ: true
      BackupRetentionPeriod: 35
      DeletionProtection: true
      EnablePerformanceInsights: true
      PerformanceInsightsRetentionPeriod: 731
      AutoMinorVersionUpgrade: false
      Tags:
        - Key: Environment
          Value: !Ref Environment
```

### DB Instance - PostgreSQL

```yaml
Resources:
  PostgreSQLDBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: postgres-instance
      DBInstanceClass: db.t3.medium
      Engine: postgres
      EngineVersion: "16.1"
      MasterUsername: !Ref MasterUsername
      MasterUserPassword: !Ref MasterUserPassword
      AllocatedStorage: "100"
      StorageType: gp3
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !Ref DBSecurityGroup
      DBParameterGroupName: !Ref DBParameterGroup
      StorageEncrypted: true
      MultiAZ: true
      BackupRetentionPeriod: 35
      DeletionProtection: true
      EnablePerformanceInsights: true
      PubliclyAccessible: false
```

### Aurora MySQL Cluster

```yaml
Resources:
  AuroraMySQLCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: aurora-mysql-cluster
      Engine: aurora-mysql
      EngineVersion: "8.0.mysql_aurora.3.02.0"
      MasterUsername: !Ref MasterUsername
      MasterUserPassword: !Ref MasterUserPassword
      DatabaseName: mydb
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !Ref DBSecurityGroup
      DBClusterParameterGroupName: !Ref AuroraClusterParameterGroup
      StorageEncrypted: true
      EngineMode: provisioned
      Port: 3306
      EnableIAMDatabaseAuthentication: true

  AuroraDBInstanceWriter:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: aurora-writer
      DBClusterIdentifier: !Ref AuroraMySQLCluster
      Engine: aurora-mysql
      DBInstanceClass: db.r5.large
      PromotionTier: 1

  AuroraDBInstanceReader:
    Type: AWS::RDS::DBInstance
    DependsOn: AuroraDBInstanceWriter
    Properties:
      DBInstanceIdentifier: aurora-reader
      DBClusterIdentifier: !Ref AuroraMySQLCluster
      Engine: aurora-mysql
      DBInstanceClass: db.r5.large
      PromotionTier: 2
```

### Aurora PostgreSQL Cluster

```yaml
Resources:
  AuroraPostgresCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: aurora-pg-cluster
      Engine: aurora-postgresql
      EngineVersion: "15.4"
      MasterUsername: !Ref MasterUsername
      MasterUserPassword: !Ref MasterUserPassword
      DatabaseName: mydb
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !Ref DBSecurityGroup
      StorageEncrypted: true
      EngineMode: provisioned
      Port: 5432

  AuroraPostgresInstanceWriter:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: aurora-pg-writer
      DBClusterIdentifier: !Ref AuroraPostgresCluster
      Engine: aurora-postgresql
      DBInstanceClass: db.r5.large
      PromotionTier: 1

  AuroraPostgresInstanceReader:
    Type: AWS::RDS::DBInstance
    DependsOn: AuroraPostgresInstanceWriter
    Properties:
      DBInstanceIdentifier: aurora-pg-reader
      DBClusterIdentifier: !Ref AuroraPostgresCluster
      Engine: aurora-postgresql
      DBInstanceClass: db.r5.large
      PromotionTier: 2
```

### Aurora Serverless Cluster

```yaml
Resources:
  AuroraServerlessCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: aurora-serverless
      Engine: aurora-mysql
      EngineVersion: "5.6.mysql_aurora.2.12.0"
      MasterUsername: !Ref MasterUsername
      MasterUserPassword: !Ref MasterUserPassword
      DatabaseName: mydb
      DBSubnetGroupName: !Ref DBSubnetGroup
      VPCSecurityGroups:
        - !Ref DBSecurityGroup
      EngineMode: serverless
      ScalingConfiguration:
        AutoPause: true
        MinCapacity: 2
        MaxCapacity: 32
        SecondsUntilAutoPause: 300
```

### DB Cluster Parameter Group (Aurora)

```yaml
Resources:
  AuroraClusterParameterGroup:
    Type: AWS::RDS::DBClusterParameterGroup
    Properties:
      Description: Custom cluster parameter group for Aurora MySQL
      Family: aurora-mysql8.0
      Parameters:
        character_set_server: utf8mb4
        collation_server: utf8mb4_unicode_ci
        max_connections: 1000
        innodb_buffer_pool_size: 2147483648
        slow_query_log: "ON"
        long_query_time: 2
```

## Security and Secrets

### Using Secrets Manager for Credentials

```yaml
Resources:
  DBCredentialsSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: !Sub ${AWS::StackName}/rds/credentials
      Description: RDS database credentials
      SecretString: !Sub |
        {
          "username": "${MasterUsername}",
          "password": "${MasterUserPassword}",
          "host": !GetAtt DBInstance.Endpoint.Address,
          "port": !GetAtt DBInstance.Endpoint.Port,
          "dbname": "mydb"
        }

  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass: db.t3.medium
      Engine: mysql
      MasterUsername: !Sub "{{resolve:secretsmanager:${DBCredentialsSecret}:SecretString:username}}"
      MasterUserPassword: !Sub "{{resolve:secretsmanager:${DBCredentialsSecret}:SecretString:password}}"
      # ...
```

### DB Security Group (for EC2-Classic)

```yaml
Resources:
  DBSecurityGroup:
    Type: AWS::RDS::DBSecurityGroup
    Properties:
      DBSecurityGroupDescription: Security group for RDS instance
      EC2VpcId: !Ref VPCId
      # For EC2-Classic, use DBSecurityGroupIngress
      DBSecurityGroupIngress:
        - EC2SecurityGroupId: !Ref AppSecurityGroup
        - EC2SecurityGroupName: default
```

### VPC Security Groups (Recommended)

For VPC deployment, use EC2 security groups instead:

```yaml
Resources:
  DBSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for RDS
      VpcId: !Ref VPCId
      GroupName: !Sub ${AWS::StackName}-rds-sg
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          SourceSecurityGroupId: !Ref AppSecurityGroup
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-rds-sg

  AppSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for application
      VpcId: !Ref VPCId
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          DestinationSecurityGroupId: !Ref DBSecurityGroup
```

## High Availability and Multi-AZ

### Multi-AZ Deployment

```yaml
Parameters:
  EnableMultiAZ:
    Type: String
    Default: true
    AllowedValues:
      - true
      - false

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      # Multi-AZ is not supported for Aurora clusters (automatic)
      MultiAZ: !Ref EnableMultiAZ
      # For multi-AZ, use a standby in a different AZ
      AvailabilityZone: !If
        - IsMultiAZ
        - !Select [1, !GetAZs '']
        - !Ref AWS::NoValue
      # For single-AZ, specify no AZ (AWS selects)
```

### Read Replicas

```yaml
Resources:
  # Primary instance
  PrimaryDBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass: db.r5.large
      Engine: mysql
      SourceDBInstanceIdentifier: !Ref ExistingDBInstance

  # Read replica in different region
  CrossRegionReadReplica:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: my-cross-region-replica
      SourceDBInstanceIdentifier: !Sub arn:aws:rds:us-west-2:${AWS::AccountId}:db:${PrimaryDBInstance}
      DBInstanceClass: db.r5.large
      Engine: mysql
```

### Enhanced Monitoring and Performance Insights

```yaml
Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      EnablePerformanceInsights: true
      PerformanceInsightsRetentionPeriod: 731
      PerformanceInsightsKMSKeyId: !Ref PerformanceInsightsKey

      # Enhanced Monitoring
      MonitoringInterval: 60
      MonitoringRoleArn: !GetAtt MonitoringRole.Arn

      # Database insights
      EnableCloudwatchLogsExports:
        - audit
        - error
        - general
        - slowquery

# IAM Role for Enhanced Monitoring
Resources:
  MonitoringRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: monitoring.rds.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole
```

## Best Practices

### Use AWS-Specific Parameter Types

Always use AWS-specific parameter types for validation and easier selection.

```yaml
Parameters:
  DBInstanceClass:
    Type: AWS::RDS::DBInstance::InstanceType
    Description: RDS instance type

  DBInstanceIdentifier:
    Type: String
    AllowedPattern: "^[a-zA-Z][a-zA-Z0-9]*$"
```

### Enable Encryption at Rest

Always enable encryption for production databases.

```yaml
Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      StorageEncrypted: true
      KmsKeyId: !Ref EncryptionKey
```

### Use Multi-AZ for Production

```yaml
Conditions:
  IsProduction: !Equals [!Ref Environment, production]

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      MultiAZ: !If [IsProduction, true, false]
      BackupRetentionPeriod: !If [IsProduction, 35, 7]
      DeletionProtection: !If [IsProduction, true, false]
```

### Enable Performance Insights

```yaml
Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      EnablePerformanceInsights: true
      PerformanceInsightsRetentionPeriod: 731
      PerformanceInsightsKMSKeyId: !Ref PK
```

### Use Proper Naming Conventions

```yaml
Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${Environment}-${Application}-rds
        - Key: Environment
          Value: !Ref Environment
        - Key: Application
          Value: !Ref ApplicationName
        - Key: ManagedBy
          Value: CloudFormation
```

### Use Secrets Manager for Credentials

```yaml
Resources:
  DBCredentials:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: !Sub ${AWS::StackName}/rds/credentials
      SecretString: !Sub '{"username":"${MasterUsername}","password":"${MasterUserPassword}"}'

  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      MasterUsername: !Sub "{{resolve:secretsmanager:${DBCredentials}:SecretString:username}}"
      MasterUserPassword: !Sub "{{resolve:secretsmanager:${DBCredentials}:SecretString:password}}"
```

### Separate Database and Application Stacks

```yaml
# database-stack.yaml - Rarely changes
AWSTemplateFormatVersion: 2010-09-09
Description: Database infrastructure (VPC, subnets, RDS instance)
Resources:
  DBSubnetGroup: AWS::RDS::DBSubnetGroup
  DBInstance: AWS::RDS::DBInstance
  DBParameterGroup: AWS::RDS::DBParameterGroup

# application-stack.yaml - Changes frequently
AWSTemplateFormatVersion: 2010-09-09
Description: Application resources
Parameters:
  DatabaseStackName:
    Type: String
Resources:
  ApplicationConfig: AWS::SSM::Parameter
```

### Use Pseudo Parameters

Use pseudo parameters for region-agnostic templates.

```yaml
Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: !Sub ${AWS::StackName}-${AWS::Region}
      Tags:
        - Key: Region
          Value: !Ref AWS::Region
        - Key: AccountId
          Value: !Ref AWS::AccountId
```

### Validate Before Deployment

```bash
# Validate template
aws cloudformation validate-template --template-body file://template.yaml

# Use cfn-lint for advanced validation
pip install cfn-lint
cfn-lint template.yaml

# Check for AWS-specific issues
cfn-lint template.yaml --region us-east-1
```

## Stack Policies

Stack policies protect critical resources from unintended updates during stack operations. For RDS databases, this is essential to prevent accidental modifications that could cause data loss or downtime.

### Basic Stack Policy

```yaml
{
  "Statement" : [
    {
      "Effect" : "Allow",
      "Action" : "Update:*",
      "Principal": "*",
      "Resource" : "*"
    },
    {
      "Effect" : "Deny",
      "Action" : "Update:*",
      "Principal": "*",
      "Resource" : "LogicalResourceId/DBInstance"
    },
    {
      "Effect" : "Deny",
      "Action" : "Update:*",
      "Principal": "*",
      "Resource" : "LogicalResourceId/DBCluster"
    }
  ]
}
```

### Stack Policy for Production RDS

```yaml
{
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "Update:*",
      "Principal": "*",
      "Resource": "*"
    },
    {
      "Effect": "Deny",
      "Action": [
        "Update:Replace",
        "Update:Delete"
      ],
      "Principal": "*",
      "Resource": "LogicalResourceId/DBInstance"
    },
    {
      "Effect": "Deny",
      "Action": [
        "Update:Replace",
        "Update:Delete"
      ],
      "Principal": "*",
      "Resource": "LogicalResourceId/DBCluster"
    },
    {
      "Effect": "Deny",
      "Action": "Update:Delete",
      "Principal": "*",
      "Resource": "LogicalResourceId/DBSubnetGroup"
    },
    {
      "Effect": "Allow",
      "Action": "Update:Modify",
      "Principal": "*",
      "Resource": "LogicalResourceId/DBInstance",
      "Condition": {
        "StringEquals": {
          "ResourceAttribute/StorageEncrypted": "true"
        }
      }
    }
  ]
}
```

### Setting Stack Policy

```bash
# Set stack policy during creation
aws cloudformation create-stack \
  --stack-name my-rds-stack \
  --template-body file://template.yaml \
  --stack-policy-body file://stack-policy.json

# Set stack policy on existing stack
aws cloudformation set-stack-policy \
  --stack-name my-rds-stack \
  --stack-policy-body file://stack-policy.json

# View current stack policy
aws cloudformation get-stack-policy \
  --stack-name my-rds-stack \
  --query StackPolicyBody \
  --output text
```

## Termination Protection

Termination protection is **critical for RDS databases** as it prevents accidental deletion that could result in data loss. This should be enabled for all production databases.

### Enabling Termination Protection

```bash
# Enable termination protection on stack creation
aws cloudformation create-stack \
  --stack-name production-rds \
  --template-body file://template.yaml \
  --enable-termination-protection

# Enable termination protection on existing stack
aws cloudformation update-termination-protection \
  --stack-name production-rds \
  --enable-termination-protection

# Check if termination protection is enabled
aws cloudformation describe-stacks \
  --stack-name production-rds \
  --query 'Stacks[0].EnableTerminationProtection' \
  --output boolean

# Disable termination protection (requires confirmation)
aws cloudformation update-termination-protection \
  --stack-name production-rds \
  --no-enable-termination-protection
```

### Termination Protection in Template

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: RDS instance with termination protection enabled

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: production-db
      DBInstanceClass: db.r5.large
      Engine: mysql
      MasterUsername: !Ref MasterUsername
      MasterUserPassword: !Ref MasterUserPassword
      StorageEncrypted: true
      MultiAZ: true
      DeletionProtection: true
      # Termination protection is set at stack level, not resource level
```

### Deletion Protection vs Termination Protection

| Feature | DeletionProtection | Termination Protection |
|---------|-------------------|------------------------|
| **Level** | Resource level (DBInstance) | Stack level |
| **Prevents** | DELETE_DB_INSTANCE API call | CloudFormation stack deletion |
| **Console UI** | Instance settings | Stack settings |
| **Override** | Cannot be overridden | Can be disabled with confirmation |
| **Recommended for** | All production RDS instances | All production stacks with RDS |

### Deletion Protection Best Practice

```yaml
Conditions:
  IsProduction: !Equals [!Ref Environment, production]

Resources:
  DBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      # Always enable deletion protection
      DeletionProtection: !If [IsProduction, true, false]
      # Additional production safeguards
      MultiAZ: !If [IsProduction, true, false]
      BackupRetentionPeriod: !If [IsProduction, 35, 7]
```

## Drift Detection

Drift detection identifies when the actual infrastructure configuration differs from the CloudFormation template. This is crucial for RDS to ensure security and compliance.

### Detecting Drift

```bash
# Detect drift on entire stack
aws cloudformation detect-stack-drift \
  --stack-name production-rds

# Detect drift on specific resources
aws cloudformation detect-stack-drift \
  --stack-name production-rds \
  --logical-resource-ids DBInstance,DBParameterGroup

# Get drift detection status
aws cloudformation describe-stack-drift-detection-status \
  --stack-drift-detection-id <detection-id>

# Check drift status for all resources
aws cloudformation describe-stack-resource-drifts \
  --stack-name production-rds
```

### Drift Detection Status Response

```json
{
  "StackResourceDrifts": [
    {
      "LogicalResourceId": "DBInstance",
      "PhysicalResourceId": "production-db-instance-id",
      "ResourceType": "AWS::RDS::DBInstance",
      "StackId": "arn:aws:cloudformation:us-east-1:123456789:stack/production-rds/...",
      "DriftStatus": "MODIFIED",
      "PropertyDifferences": [
        {
          "PropertyPath": "MultiAZ",
          "ExpectedValue": "true",
          "ActualValue": "false"
        },
        {
          "PropertyPath": "BackupRetentionPeriod",
          "ExpectedValue": "35",
          "ActualValue": "7"
        }
      ]
    }
  ]
}
```

### Automated Drift Detection Schedule

```bash
# Create a Lambda function to check drift weekly
# and send SNS notification if drift is detected

aws events put-rule \
  --name rds-drift-detection \
  --schedule-expression "rate(7 days)"

aws events put-targets \
  --rule rds-drift-detection \
  --targets "Id"="1","Arn"="arn:aws:lambda:us-east-1:123456789:function/drift-checker"
```

### Drift Detection Script

```bash
#!/bin/bash
# check-rds-drift.sh

STACK_NAME=$1
DRIFT_STATUS=$(aws cloudformation detect-stack-drift \
  --stack-name $STACK_NAME \
  --query StackDriftStatus \
  --output text 2>/dev/null)

if [ "$DRIFT_STATUS" == "DRIFTED" ]; then
  echo "Drift detected on stack $STACK_NAME"
  aws cloudformation describe-stack-resources \
    --stack-name $STACK_NAME \
    --query 'StackResources[?ResourceStatusReason!=`null`]' \
    --output table
  # Send notification
  aws sns publish \
    --topic-arn arn:aws:sns:us-east-1:123456789:rds-drift-alert \
    --message "Drift detected on stack $STACK_NAME"
else
  echo "No drift detected on stack $STACK_NAME"
fi
```

## Change Sets

Change sets allow you to preview how proposed changes will affect your stack before execution. This is essential for RDS to understand potential impact.

### Creating and Viewing a Change Set

```bash
# Create change set for stack update
aws cloudformation create-change-set \
  --stack-name production-rds \
  --change-set-name preview-changes \
  --template-body file://updated-template.yaml \
  --capabilities CAPABILITY_IAM \
  --change-set-type UPDATE

# List change sets for a stack
aws cloudformation list-change-sets \
  --stack-name production-rds

# Describe change set
aws cloudformation describe-change-set \
  --stack-name production-rds \
  --change-set-name preview-changes

# Execute change set
aws cloudformation execute-change-set \
  --stack-name production-rds \
  --change-set-name preview-changes

# Delete change set (if not executing)
aws cloudformation delete-change-set \
  --stack-name production-rds \
  --change-set-name preview-changes
```

### Change Set Response Example

```json
{
  "ChangeSetName": "preview-changes",
  "ChangeSetId": "arn:aws:cloudformation:us-east-1:123456789:changeSet/...",
  "StackId": "arn:aws:cloudformation:us-east-1:123456789:stack/...",
  "Status": "CREATE_COMPLETE",
  "Changes": [
    {
      "Type": "Resource",
      "ResourceChange": {
        "Action": "Modify",
        "LogicalResourceId": "DBInstance",
        "PhysicalResourceId": "production-db",
        "ResourceType": "AWS::RDS::DBInstance",
        "Replacement": "False",
        "Scope": [
          "Properties"
        ],
        "Details": [
          {
            "Target": {
              "Attribute": "Properties",
              "Name": "MultiAZ"
            },
            "Evaluation": "Static",
            "ChangeSource": "Parameter",
            "BeforeValue": "false",
            "AfterValue": "true"
          }
        ]
      }
    }
  ]
}
```

### Change Set for RDS Modifications

```bash
# Change set that will modify RDS instance class
aws cloudformation create-change-set \
  --stack-name production-rds \
  --change-set-name modify-instance-class \
  --template-body file://modify-instance-template.yaml \
  --parameters parameter-overrides DBInstanceClass=db.r5.xlarge

# Change set for adding read replica
aws cloudformation create-change-set \
  --stack-name production-rds \
  --change-set-name add-read-replica \
  --template-body file://add-replica-template.yaml

# Change set that requires replacement (causes downtime)
aws cloudformation create-change-set \
  --stack-name production-rds \
  --change-set-name change-engine-version \
  --template-body file://change-version-template.yaml
```

### Change Set Types

| Change Set Type | Description | Use Case |
|----------------|-------------|----------|
| `UPDATE` | Creates changes for existing stack | Modifying existing resources |
| `CREATE` | Simulates stack creation | Validating new templates |
| `IMPORT` | Imports existing resources | Moving resources to CloudFormation |

### Change Set Best Practices for RDS

```bash
# Always create change set before updating RDS
aws cloudformation create-change-set \
  --stack-name production-rds \
  --change-set-name pre-update-preview \
  --template-body file://updated-template.yaml

# Review changes carefully
aws cloudformation describe-change-set \
  --stack-name production-rds \
  --change-set-name pre-update-preview \
  --query 'Changes[].ResourceChange'

# Check for replacement operations
aws cloudformation describe-change-set \
  --stack-name production-rds \
  --change-set-name pre-update-preview \
  --query 'Changes[?ResourceChange.Replacement==`True`]'

# Only execute if changes are acceptable
aws cloudformation execute-change-set \
  --stack-name production-rds \
  --change-set-name pre-update-preview
```

## Related Resources

- For advanced patterns: See [EXAMPLES.md](EXAMPLES.md)
- For reference: See [REFERENCE.md](REFERENCE.md)
- AWS CloudFormation User Guide: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/
- RDS Documentation: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/
- RDS Best Practices: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_BestPractices.html
- Aurora Documentation: https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/

## Constraints and Warnings

### Resource Limits

- **Instance Storage Limits**: Maximum storage size varies by instance class and engine
- **Database Name Limits**: Database name identifiers have specific length and character requirements
- **Parameter Groups**: Maximum number of DB parameter groups per account
- **Option Groups**: Some options are not compatible with specific database engines

### Operational Constraints

- **Instance Replacement**: Certain modifications (like engine version upgrade) require instance replacement with downtime
- **Snapshot Storage**: Manual snapshots incur storage costs even after instance deletion
- **Multi-AZ Deployment**: Multi-AZ deployments double compute costs but provide HA
- **Backup Retention**: Changing backup retention period affects storage costs

### Security Constraints

- **Master Credentials**: Master user password cannot be retrieved after creation; must be reset if lost
- **Encryption at Rest**: Once enabled, encryption cannot be disabled for RDS storage
- **VPC Access**: RDS instances must be in VPC; public access not recommended
- **Security Groups**: Security group rules must allow traffic from application tier only

### Cost Considerations

- **Instance Class Costs**: Larger instance classes significantly increase hourly costs
- **Multi-AZ Premium**: Multi-AZ deployments cost approximately double single-AZ
- **IOPS Costs**: Provisioned IOPS (io1) storage type significantly increases costs
- **Backup Storage**: Automated backups beyond free tier incur monthly GB storage costs
- **Data Transfer**: Inter-AZ data transfer for Multi-AZ replication incurs costs

### Performance Constraints

- **Storage Autoscaling**: Storage autoscaling has minimum and maximum increments
- **Connection Limits**: Maximum connections vary by instance class and database engine
- **Maintenance Windows**: Maintenance windows may cause brief service interruptions
- **Read Replica Lag**: Read replicas may lag behind primary by seconds to minutes

### Availability Constraints

- **Region Availability**: Not all database engines are available in all regions
- **Version Support**: Older database versions may be deprecated and require upgrades
- **Instance Type Availability**: Some instance types may not be available in all AZs

## Additional Files

Overview

This skill provides battle-tested AWS CloudFormation patterns for provisioning Amazon RDS databases. It covers single-instance and cluster deployments (MySQL, PostgreSQL, Aurora, MariaDB), multi-AZ setups, parameter and subnet groups, security and backup configuration, and template structuring for reusable stacks. Use it to accelerate reliable, production-ready RDS infrastructure as code.

How this skill works

The skill supplies CloudFormation template patterns and examples that define Parameters, Mappings, Conditions, Resources, and Outputs for RDS workloads. It demonstrates DBInstance and DBCluster resources, DBSubnetGroup and DBParameterGroup configuration, VPC security group integration, Secrets Manager for credentials, and cross-stack outputs for modular stacks. Templates include validation rules, recommended defaults, and production settings like Multi-AZ, backups, and monitoring.

When to use it

  • Provision a new RDS instance or Aurora cluster with a reusable CloudFormation template
  • Build multi-AZ or read-replica architectures for availability and scale
  • Create DB parameter groups, option groups, and subnet groups for VPC deployments
  • Integrate Secrets Manager for credential rotation and secure parameters
  • Organize templates with Parameters, Mappings, Conditions, and Outputs for modular stacks

Best practices

  • Use AWS-specific parameter types and constraints for safer console input and validation
  • Store credentials in AWS Secrets Manager and reference them from templates
  • Define DBSubnetGroup with private subnets and attach least-privilege security groups
  • Enable Multi-AZ, automated backups, and Performance Insights for production workloads
  • Expose only necessary Outputs for cross-stack references and avoid leaking secrets

Example use cases

  • Quickly generate a MySQL single-instance template for development or staging
  • Deploy an Aurora MySQL cluster with a writer and reader for horizontally scaled reads
  • Migrate a PostgreSQL deployment to Multi-AZ with automated backups and monitoring
  • Build modular stacks: networking in one stack, DB in another, connecting via Outputs
  • Create parameterized templates that select engine and version via SSM or allowed lists

FAQ

Should I store DB passwords directly in templates?

No. Use AWS Secrets Manager and reference secrets in CloudFormation to avoid exposing credentials.

When should I use DB clusters vs single instances?

Choose DB clusters (Aurora or read-replica setups) for high read throughput and automatic scaling; use single instances for small, cost-sensitive workloads.