Create AWS RDS Database Instances

The aws:rds/instance:Instance resource, part of the Pulumi AWS provider, provisions an RDS database instance: its engine, compute class, storage, and network placement. This guide focuses on three capabilities: basic instance creation, storage autoscaling, and Secrets Manager password management.

RDS instances run in VPC subnet groups with security groups, and may reference KMS keys for encryption. The examples are intentionally small. Combine them with your own VPC configuration, backup policies, and monitoring setup.

Create a MySQL instance with basic configuration

Most deployments start with engine selection, storage sizing, and master user credentials.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const _default = new aws.rds.Instance("default", {
    allocatedStorage: 10,
    dbName: "mydb",
    engine: "mysql",
    engineVersion: "8.0",
    instanceClass: aws.rds.InstanceType.T3_Micro,
    username: "foo",
    password: "foobarbaz",
    parameterGroupName: "default.mysql8.0",
    skipFinalSnapshot: true,
});
import pulumi
import pulumi_aws as aws

default = aws.rds.Instance("default",
    allocated_storage=10,
    db_name="mydb",
    engine="mysql",
    engine_version="8.0",
    instance_class=aws.rds.InstanceType.T3_MICRO,
    username="foo",
    password="foobarbaz",
    parameter_group_name="default.mysql8.0",
    skip_final_snapshot=True)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := rds.NewInstance(ctx, "default", &rds.InstanceArgs{
			AllocatedStorage:   pulumi.Int(10),
			DbName:             pulumi.String("mydb"),
			Engine:             pulumi.String("mysql"),
			EngineVersion:      pulumi.String("8.0"),
			InstanceClass:      pulumi.String(rds.InstanceType_T3_Micro),
			Username:           pulumi.String("foo"),
			Password:           pulumi.String("foobarbaz"),
			ParameterGroupName: pulumi.String("default.mysql8.0"),
			SkipFinalSnapshot:  pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var @default = new Aws.Rds.Instance("default", new()
    {
        AllocatedStorage = 10,
        DbName = "mydb",
        Engine = "mysql",
        EngineVersion = "8.0",
        InstanceClass = Aws.Rds.InstanceType.T3_Micro,
        Username = "foo",
        Password = "foobarbaz",
        ParameterGroupName = "default.mysql8.0",
        SkipFinalSnapshot = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.Instance;
import com.pulumi.aws.rds.InstanceArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Instance("default", InstanceArgs.builder()
            .allocatedStorage(10)
            .dbName("mydb")
            .engine("mysql")
            .engineVersion("8.0")
            .instanceClass("db.t3.micro")
            .username("foo")
            .password("foobarbaz")
            .parameterGroupName("default.mysql8.0")
            .skipFinalSnapshot(true)
            .build());

    }
}
resources:
  default:
    type: aws:rds:Instance
    properties:
      allocatedStorage: 10
      dbName: mydb
      engine: mysql
      engineVersion: '8.0'
      instanceClass: db.t3.micro
      username: foo
      password: foobarbaz
      parameterGroupName: default.mysql8.0
      skipFinalSnapshot: true

The engine and engineVersion specify the database software. The instanceClass determines compute capacity. The allocatedStorage sets initial disk size in GiB. The username and password create the master user; note that password appears in plain text in state files. The parameterGroupName references a parameter group that controls engine behavior.

Enable automatic storage scaling

When database growth is unpredictable, storage autoscaling expands capacity automatically without downtime.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.rds.Instance("example", {
    allocatedStorage: 50,
    maxAllocatedStorage: 100,
});
import pulumi
import pulumi_aws as aws

example = aws.rds.Instance("example",
    allocated_storage=50,
    max_allocated_storage=100)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := rds.NewInstance(ctx, "example", &rds.InstanceArgs{
			AllocatedStorage:    pulumi.Int(50),
			MaxAllocatedStorage: pulumi.Int(100),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Rds.Instance("example", new()
    {
        AllocatedStorage = 50,
        MaxAllocatedStorage = 100,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.Instance;
import com.pulumi.aws.rds.InstanceArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Instance("example", InstanceArgs.builder()
            .allocatedStorage(50)
            .maxAllocatedStorage(100)
            .build());

    }
}
resources:
  example:
    type: aws:rds:Instance
    properties:
      allocatedStorage: 50
      maxAllocatedStorage: 100

Setting maxAllocatedStorage higher than allocatedStorage enables autoscaling. RDS monitors storage usage and grows the volume when space runs low, up to the maximum you specify. Once configured, manual changes to allocatedStorage are ignored as the storage scales dynamically.

Store master password in Secrets Manager

Instead of managing passwords in your code, delegate password management to AWS Secrets Manager.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const _default = new aws.rds.Instance("default", {
    allocatedStorage: 10,
    dbName: "mydb",
    engine: "mysql",
    engineVersion: "8.0",
    instanceClass: aws.rds.InstanceType.T3_Micro,
    manageMasterUserPassword: true,
    username: "foo",
    parameterGroupName: "default.mysql8.0",
});
import pulumi
import pulumi_aws as aws

default = aws.rds.Instance("default",
    allocated_storage=10,
    db_name="mydb",
    engine="mysql",
    engine_version="8.0",
    instance_class=aws.rds.InstanceType.T3_MICRO,
    manage_master_user_password=True,
    username="foo",
    parameter_group_name="default.mysql8.0")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := rds.NewInstance(ctx, "default", &rds.InstanceArgs{
			AllocatedStorage:         pulumi.Int(10),
			DbName:                   pulumi.String("mydb"),
			Engine:                   pulumi.String("mysql"),
			EngineVersion:            pulumi.String("8.0"),
			InstanceClass:            pulumi.String(rds.InstanceType_T3_Micro),
			ManageMasterUserPassword: pulumi.Bool(true),
			Username:                 pulumi.String("foo"),
			ParameterGroupName:       pulumi.String("default.mysql8.0"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var @default = new Aws.Rds.Instance("default", new()
    {
        AllocatedStorage = 10,
        DbName = "mydb",
        Engine = "mysql",
        EngineVersion = "8.0",
        InstanceClass = Aws.Rds.InstanceType.T3_Micro,
        ManageMasterUserPassword = true,
        Username = "foo",
        ParameterGroupName = "default.mysql8.0",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.Instance;
import com.pulumi.aws.rds.InstanceArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Instance("default", InstanceArgs.builder()
            .allocatedStorage(10)
            .dbName("mydb")
            .engine("mysql")
            .engineVersion("8.0")
            .instanceClass("db.t3.micro")
            .manageMasterUserPassword(true)
            .username("foo")
            .parameterGroupName("default.mysql8.0")
            .build());

    }
}
resources:
  default:
    type: aws:rds:Instance
    properties:
      allocatedStorage: 10
      dbName: mydb
      engine: mysql
      engineVersion: '8.0'
      instanceClass: db.t3.micro
      manageMasterUserPassword: true
      username: foo
      parameterGroupName: default.mysql8.0

Setting manageMasterUserPassword to true tells RDS to generate a password and store it in Secrets Manager. You omit the password property entirely. RDS creates a secret, rotates it automatically, and provides the secret ARN in the masterUserSecrets output. Applications retrieve the password from Secrets Manager at runtime.

Use a custom KMS key for password encryption

Organizations with encryption requirements can specify their own KMS key for the Secrets Manager secret.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.kms.Key("example", {description: "Example KMS Key"});
const _default = new aws.rds.Instance("default", {
    allocatedStorage: 10,
    dbName: "mydb",
    engine: "mysql",
    engineVersion: "8.0",
    instanceClass: aws.rds.InstanceType.T3_Micro,
    manageMasterUserPassword: true,
    masterUserSecretKmsKeyId: example.keyId,
    username: "foo",
    parameterGroupName: "default.mysql8.0",
});
import pulumi
import pulumi_aws as aws

example = aws.kms.Key("example", description="Example KMS Key")
default = aws.rds.Instance("default",
    allocated_storage=10,
    db_name="mydb",
    engine="mysql",
    engine_version="8.0",
    instance_class=aws.rds.InstanceType.T3_MICRO,
    manage_master_user_password=True,
    master_user_secret_kms_key_id=example.key_id,
    username="foo",
    parameter_group_name="default.mysql8.0")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/kms"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := kms.NewKey(ctx, "example", &kms.KeyArgs{
			Description: pulumi.String("Example KMS Key"),
		})
		if err != nil {
			return err
		}
		_, err = rds.NewInstance(ctx, "default", &rds.InstanceArgs{
			AllocatedStorage:         pulumi.Int(10),
			DbName:                   pulumi.String("mydb"),
			Engine:                   pulumi.String("mysql"),
			EngineVersion:            pulumi.String("8.0"),
			InstanceClass:            pulumi.String(rds.InstanceType_T3_Micro),
			ManageMasterUserPassword: pulumi.Bool(true),
			MasterUserSecretKmsKeyId: example.KeyId,
			Username:                 pulumi.String("foo"),
			ParameterGroupName:       pulumi.String("default.mysql8.0"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Kms.Key("example", new()
    {
        Description = "Example KMS Key",
    });

    var @default = new Aws.Rds.Instance("default", new()
    {
        AllocatedStorage = 10,
        DbName = "mydb",
        Engine = "mysql",
        EngineVersion = "8.0",
        InstanceClass = Aws.Rds.InstanceType.T3_Micro,
        ManageMasterUserPassword = true,
        MasterUserSecretKmsKeyId = example.KeyId,
        Username = "foo",
        ParameterGroupName = "default.mysql8.0",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.kms.Key;
import com.pulumi.aws.kms.KeyArgs;
import com.pulumi.aws.rds.Instance;
import com.pulumi.aws.rds.InstanceArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Key("example", KeyArgs.builder()
            .description("Example KMS Key")
            .build());

        var default_ = new Instance("default", InstanceArgs.builder()
            .allocatedStorage(10)
            .dbName("mydb")
            .engine("mysql")
            .engineVersion("8.0")
            .instanceClass("db.t3.micro")
            .manageMasterUserPassword(true)
            .masterUserSecretKmsKeyId(example.keyId())
            .username("foo")
            .parameterGroupName("default.mysql8.0")
            .build());

    }
}
resources:
  example:
    type: aws:kms:Key
    properties:
      description: Example KMS Key
  default:
    type: aws:rds:Instance
    properties:
      allocatedStorage: 10
      dbName: mydb
      engine: mysql
      engineVersion: '8.0'
      instanceClass: db.t3.micro
      manageMasterUserPassword: true
      masterUserSecretKmsKeyId: ${example.keyId}
      username: foo
      parameterGroupName: default.mysql8.0

The masterUserSecretKmsKeyId property points to your KMS key. RDS uses this key to encrypt the secret containing the master password. This extends the Secrets Manager integration from the previous example by adding control over encryption keys.

Beyond these examples

These snippets focus on specific instance-level features: basic instance provisioning, storage autoscaling, and Secrets Manager password management. They’re intentionally minimal rather than full database deployments.

The examples typically assume pre-existing infrastructure such as VPC and subnet groups, and KMS keys for custom encryption. They focus on configuring the instance rather than provisioning the surrounding network and security infrastructure.

To keep things focused, common RDS patterns are omitted, including:

  • VPC and security group configuration (vpcSecurityGroupIds, dbSubnetGroupName)
  • Backup and maintenance windows (backupRetentionPeriod, backupWindow, maintenanceWindow)
  • Encryption at rest (storageEncrypted, kmsKeyId)
  • Read replicas and cross-region replication (replicateSourceDb)
  • Performance Insights and Enhanced Monitoring
  • Blue/Green deployments for low-downtime updates

These omissions are intentional: the goal is to illustrate how each RDS feature is wired, not provide drop-in production database modules. See the RDS Instance resource reference for all available configuration options.

Let's create AWS RDS Database Instances

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Updates & Maintenance
Will applying changes to my RDS instance cause downtime?
By default, changes are applied during the next maintenance window without immediate downtime. Setting apply_immediately to true applies changes immediately but causes a brief downtime as the server reboots.
How can I minimize downtime during updates?
Enable low-downtime updates by setting blue_green_update.enabled to true. This requires MySQL, MariaDB, or PostgreSQL engines, backups enabled (backup_retention_period > 0), and the instance must have no replicas.
What's required to upgrade to a major engine version?
Set allow_major_version_upgrade to true when upgrading the major version of an engine.
Security & Password Management
How do I avoid storing the master password in Pulumi state?
Set manage_master_user_password to true to have RDS manage the password via Secrets Manager. You must remove the password field when enabling this, as they cannot be used together.
Can I change the Performance Insights KMS key after creation?
No, once performance_insights_kms_key_id is set, it can never be changed. Choose your KMS key carefully during initial configuration.
Read Replicas
How do I create a cross-region encrypted read replica?
Set replicate_source_db to the source DB’s arn (not identifier) and specify kms_key_id with the destination region’s KMS key ARN.
What happens if I remove replicate_source_db from my configuration?
Removing replicate_source_db from an existing replica will promote it to a fully standalone database. This is a one-way operation.
Storage Configuration
How do I enable storage autoscaling?
Set max_allocated_storage to a value greater than or equal to allocated_storage. Pulumi will automatically ignore changes to allocated_storage as storage scales dynamically. Set to 0 to explicitly disable autoscaling.
Why can't I specify IOPS or storage throughput for my gp3 storage?
For gp3 storage, iops and storage_throughput cannot be specified if allocated_storage is below a per-engine threshold. See the RDS User Guide for specific thresholds.
What storage types are available and when should I use each?
Available types: standard (magnetic), gp2 (general purpose SSD), gp3 (newer general purpose SSD), io1 (provisioned IOPS SSD), or io2 (block express provisioned IOPS SSD). The default is io1 if iops is specified, otherwise gp2.
Backups & Deletion
What backup retention is required for read replicas and Blue/Green deployments?
backup_retention_period must be greater than 0 (between 0-35 days) if the database is used as a source for read replicas, uses low-downtime updates, or will use Blue/Green deployments. Default is 0.
How do I prevent a final snapshot when deleting my instance?
Set skip_final_snapshot to true. If false (default), you must provide final_snapshot_identifier. Note that final snapshots cannot be created when deleting a read replica.
Immutability & Constraints
What properties can't be changed after creating an RDS instance?
The following properties are immutable: availability_zone, backup_target, character_set_name, custom_iam_instance_profile, db_name, engine, kms_key_id, nchar_character_set_name, restore_to_point_in_time, snapshot_identifier, storage_encrypted, timezone, and username.

Using a different cloud?

Explore database guides for other cloud providers: