Create AWS RDS Database Instances

The aws:rds/instance:Instance resource, part of the Pulumi AWS provider, provisions an RDS database instance: its engine, storage, compute capacity, and network placement. This guide focuses on four capabilities: basic MySQL instance creation, storage autoscaling, Secrets Manager password management, and RDS Custom for Oracle with replicas.

RDS instances run in VPC subnet groups with security groups controlling network access. They may reference IAM roles for monitoring or Active Directory integration, KMS keys for encryption, and parameter groups for engine configuration. The examples are intentionally small. Combine them with your own VPC infrastructure, backup policies, and monitoring configuration.

Create a MySQL instance with basic configuration

Most deployments start with engine selection, storage sizing, and credentials before adding features like backups or encryption.

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 establish master credentials; note that password appears in state files. For production, use manageMasterUserPassword instead to delegate credential management to Secrets Manager. The skipFinalSnapshot setting prevents snapshot creation on deletion, useful for testing but risky for production data.

Enable automatic storage scaling

When database growth is unpredictable, storage autoscaling expands capacity automatically as space fills.

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 disk usage and scales storage incrementally up to the maximum. Once configured, manual changes to allocatedStorage are ignored since the system manages capacity dynamically. Setting maxAllocatedStorage to 0 explicitly disables autoscaling.

Store master password in Secrets Manager

Delegating password management to Secrets Manager removes credentials from infrastructure code and enables centralized rotation.

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

The manageMasterUserPassword property instructs RDS to create a secret in Secrets Manager containing the master password. You cannot specify both manageMasterUserPassword and password; they’re mutually exclusive. RDS handles password generation and storage. Applications retrieve credentials from Secrets Manager using the secret ARN exposed in the masterUserSecrets output property.

Deploy RDS Custom for Oracle with read replica

RDS Custom for Oracle provides OS-level access for applications requiring custom configurations or third-party software installations.

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

// Lookup the available instance classes for the custom engine for the region being operated in
const custom_oracle = aws.rds.getOrderableDbInstance({
    engine: "custom-oracle-ee",
    engineVersion: "19.c.ee.002",
    licenseModel: "bring-your-own-license",
    storageType: "gp3",
    preferredInstanceClasses: [
        "db.r5.xlarge",
        "db.r5.2xlarge",
        "db.r5.4xlarge",
    ],
});
// The RDS instance resource requires an ARN. Look up the ARN of the KMS key associated with the CEV.
const byId = aws.kms.getKey({
    keyId: "example-ef278353ceba4a5a97de6784565b9f78",
});
const _default = new aws.rds.Instance("default", {
    allocatedStorage: 50,
    autoMinorVersionUpgrade: false,
    customIamInstanceProfile: "AWSRDSCustomInstanceProfile",
    backupRetentionPeriod: 7,
    dbSubnetGroupName: dbSubnetGroupName,
    engine: custom_oracle.then(custom_oracle => custom_oracle.engine),
    engineVersion: custom_oracle.then(custom_oracle => custom_oracle.engineVersion),
    identifier: "ee-instance-demo",
    instanceClass: custom_oracle.then(custom_oracle => custom_oracle.instanceClass).apply((x) => aws.rds.InstanceType[x]),
    kmsKeyId: byId.then(byId => byId.arn),
    licenseModel: custom_oracle.then(custom_oracle => custom_oracle.licenseModel),
    multiAz: false,
    password: "avoid-plaintext-passwords",
    username: "test",
    storageEncrypted: true,
});
const test_replica = new aws.rds.Instance("test-replica", {
    replicateSourceDb: _default.identifier,
    replicaMode: "mounted",
    autoMinorVersionUpgrade: false,
    customIamInstanceProfile: "AWSRDSCustomInstanceProfile",
    backupRetentionPeriod: 7,
    identifier: "ee-instance-replica",
    instanceClass: custom_oracle.then(custom_oracle => custom_oracle.instanceClass).apply((x) => aws.rds.InstanceType[x]),
    kmsKeyId: byId.then(byId => byId.arn),
    multiAz: false,
    skipFinalSnapshot: true,
    storageEncrypted: true,
});
import pulumi
import pulumi_aws as aws

# Lookup the available instance classes for the custom engine for the region being operated in
custom_oracle = aws.rds.get_orderable_db_instance(engine="custom-oracle-ee",
    engine_version="19.c.ee.002",
    license_model="bring-your-own-license",
    storage_type="gp3",
    preferred_instance_classes=[
        "db.r5.xlarge",
        "db.r5.2xlarge",
        "db.r5.4xlarge",
    ])
# The RDS instance resource requires an ARN. Look up the ARN of the KMS key associated with the CEV.
by_id = aws.kms.get_key(key_id="example-ef278353ceba4a5a97de6784565b9f78")
default = aws.rds.Instance("default",
    allocated_storage=50,
    auto_minor_version_upgrade=False,
    custom_iam_instance_profile="AWSRDSCustomInstanceProfile",
    backup_retention_period=7,
    db_subnet_group_name=db_subnet_group_name,
    engine=custom_oracle.engine,
    engine_version=custom_oracle.engine_version,
    identifier="ee-instance-demo",
    instance_class=custom_oracle.instance_class.apply(lambda x: aws.rds.InstanceType(x)),
    kms_key_id=by_id.arn,
    license_model=custom_oracle.license_model,
    multi_az=False,
    password="avoid-plaintext-passwords",
    username="test",
    storage_encrypted=True)
test_replica = aws.rds.Instance("test-replica",
    replicate_source_db=default.identifier,
    replica_mode="mounted",
    auto_minor_version_upgrade=False,
    custom_iam_instance_profile="AWSRDSCustomInstanceProfile",
    backup_retention_period=7,
    identifier="ee-instance-replica",
    instance_class=custom_oracle.instance_class.apply(lambda x: aws.rds.InstanceType(x)),
    kms_key_id=by_id.arn,
    multi_az=False,
    skip_final_snapshot=True,
    storage_encrypted=True)
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 {
		// Lookup the available instance classes for the custom engine for the region being operated in
		custom_oracle, err := rds.GetOrderableDbInstance(ctx, &rds.GetOrderableDbInstanceArgs{
			Engine:        "custom-oracle-ee",
			EngineVersion: pulumi.StringRef("19.c.ee.002"),
			LicenseModel:  pulumi.StringRef("bring-your-own-license"),
			StorageType:   pulumi.StringRef("gp3"),
			PreferredInstanceClasses: []string{
				"db.r5.xlarge",
				"db.r5.2xlarge",
				"db.r5.4xlarge",
			},
		}, nil)
		if err != nil {
			return err
		}
		// The RDS instance resource requires an ARN. Look up the ARN of the KMS key associated with the CEV.
		byId, err := kms.LookupKey(ctx, &kms.LookupKeyArgs{
			KeyId: "example-ef278353ceba4a5a97de6784565b9f78",
		}, nil)
		if err != nil {
			return err
		}
		_default, err := rds.NewInstance(ctx, "default", &rds.InstanceArgs{
			AllocatedStorage:         pulumi.Int(50),
			AutoMinorVersionUpgrade:  pulumi.Bool(false),
			CustomIamInstanceProfile: pulumi.String("AWSRDSCustomInstanceProfile"),
			BackupRetentionPeriod:    pulumi.Int(7),
			DbSubnetGroupName:        pulumi.Any(dbSubnetGroupName),
			Engine:                   pulumi.String(custom_oracle.Engine),
			EngineVersion:            pulumi.String(custom_oracle.EngineVersion),
			Identifier:               pulumi.String("ee-instance-demo"),
			InstanceClass:            custom_oracle.InstanceClass.ApplyT(func(x *string) rds.InstanceType { return rds.InstanceType(*x) }).(rds.InstanceTypeOutput),
			KmsKeyId:                 pulumi.String(byId.Arn),
			LicenseModel:             pulumi.String(custom_oracle.LicenseModel),
			MultiAz:                  pulumi.Bool(false),
			Password:                 pulumi.String("avoid-plaintext-passwords"),
			Username:                 pulumi.String("test"),
			StorageEncrypted:         pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = rds.NewInstance(ctx, "test-replica", &rds.InstanceArgs{
			ReplicateSourceDb:        _default.Identifier,
			ReplicaMode:              pulumi.String("mounted"),
			AutoMinorVersionUpgrade:  pulumi.Bool(false),
			CustomIamInstanceProfile: pulumi.String("AWSRDSCustomInstanceProfile"),
			BackupRetentionPeriod:    pulumi.Int(7),
			Identifier:               pulumi.String("ee-instance-replica"),
			InstanceClass:            custom_oracle.InstanceClass.ApplyT(func(x *string) rds.InstanceType { return rds.InstanceType(*x) }).(rds.InstanceTypeOutput),
			KmsKeyId:                 pulumi.String(byId.Arn),
			MultiAz:                  pulumi.Bool(false),
			SkipFinalSnapshot:        pulumi.Bool(true),
			StorageEncrypted:         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(() => 
{
    // Lookup the available instance classes for the custom engine for the region being operated in
    var custom_oracle = Aws.Rds.GetOrderableDbInstance.Invoke(new()
    {
        Engine = "custom-oracle-ee",
        EngineVersion = "19.c.ee.002",
        LicenseModel = "bring-your-own-license",
        StorageType = "gp3",
        PreferredInstanceClasses = new[]
        {
            "db.r5.xlarge",
            "db.r5.2xlarge",
            "db.r5.4xlarge",
        },
    });

    // The RDS instance resource requires an ARN. Look up the ARN of the KMS key associated with the CEV.
    var byId = Aws.Kms.GetKey.Invoke(new()
    {
        KeyId = "example-ef278353ceba4a5a97de6784565b9f78",
    });

    var @default = new Aws.Rds.Instance("default", new()
    {
        AllocatedStorage = 50,
        AutoMinorVersionUpgrade = false,
        CustomIamInstanceProfile = "AWSRDSCustomInstanceProfile",
        BackupRetentionPeriod = 7,
        DbSubnetGroupName = dbSubnetGroupName,
        Engine = custom_oracle.Apply(custom_oracle => custom_oracle.Apply(getOrderableDbInstanceResult => getOrderableDbInstanceResult.Engine)),
        EngineVersion = custom_oracle.Apply(custom_oracle => custom_oracle.Apply(getOrderableDbInstanceResult => getOrderableDbInstanceResult.EngineVersion)),
        Identifier = "ee-instance-demo",
        InstanceClass = custom_oracle.Apply(custom_oracle => custom_oracle.Apply(getOrderableDbInstanceResult => getOrderableDbInstanceResult.InstanceClass)).Apply(System.Enum.Parse<Aws.Rds.InstanceType>),
        KmsKeyId = byId.Apply(getKeyResult => getKeyResult.Arn),
        LicenseModel = custom_oracle.Apply(custom_oracle => custom_oracle.Apply(getOrderableDbInstanceResult => getOrderableDbInstanceResult.LicenseModel)),
        MultiAz = false,
        Password = "avoid-plaintext-passwords",
        Username = "test",
        StorageEncrypted = true,
    });

    var test_replica = new Aws.Rds.Instance("test-replica", new()
    {
        ReplicateSourceDb = @default.Identifier,
        ReplicaMode = "mounted",
        AutoMinorVersionUpgrade = false,
        CustomIamInstanceProfile = "AWSRDSCustomInstanceProfile",
        BackupRetentionPeriod = 7,
        Identifier = "ee-instance-replica",
        InstanceClass = custom_oracle.Apply(custom_oracle => custom_oracle.Apply(getOrderableDbInstanceResult => getOrderableDbInstanceResult.InstanceClass)).Apply(System.Enum.Parse<Aws.Rds.InstanceType>),
        KmsKeyId = byId.Apply(getKeyResult => getKeyResult.Arn),
        MultiAz = false,
        SkipFinalSnapshot = true,
        StorageEncrypted = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.RdsFunctions;
import com.pulumi.aws.rds.inputs.GetOrderableDbInstanceArgs;
import com.pulumi.aws.kms.KmsFunctions;
import com.pulumi.aws.kms.inputs.GetKeyArgs;
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) {
        // Lookup the available instance classes for the custom engine for the region being operated in
        final var custom-oracle = RdsFunctions.getOrderableDbInstance(GetOrderableDbInstanceArgs.builder()
            .engine("custom-oracle-ee")
            .engineVersion("19.c.ee.002")
            .licenseModel("bring-your-own-license")
            .storageType("gp3")
            .preferredInstanceClasses(            
                "db.r5.xlarge",
                "db.r5.2xlarge",
                "db.r5.4xlarge")
            .build());

        // The RDS instance resource requires an ARN. Look up the ARN of the KMS key associated with the CEV.
        final var byId = KmsFunctions.getKey(GetKeyArgs.builder()
            .keyId("example-ef278353ceba4a5a97de6784565b9f78")
            .build());

        var default_ = new Instance("default", InstanceArgs.builder()
            .allocatedStorage(50)
            .autoMinorVersionUpgrade(false)
            .customIamInstanceProfile("AWSRDSCustomInstanceProfile")
            .backupRetentionPeriod(7)
            .dbSubnetGroupName(dbSubnetGroupName)
            .engine(custom_oracle.engine())
            .engineVersion(custom_oracle.engineVersion())
            .identifier("ee-instance-demo")
            .instanceClass(custom_oracle.instanceClass())
            .kmsKeyId(byId.arn())
            .licenseModel(custom_oracle.licenseModel())
            .multiAz(false)
            .password("avoid-plaintext-passwords")
            .username("test")
            .storageEncrypted(true)
            .build());

        var test_replica = new Instance("test-replica", InstanceArgs.builder()
            .replicateSourceDb(default_.identifier())
            .replicaMode("mounted")
            .autoMinorVersionUpgrade(false)
            .customIamInstanceProfile("AWSRDSCustomInstanceProfile")
            .backupRetentionPeriod(7)
            .identifier("ee-instance-replica")
            .instanceClass(custom_oracle.instanceClass())
            .kmsKeyId(byId.arn())
            .multiAz(false)
            .skipFinalSnapshot(true)
            .storageEncrypted(true)
            .build());

    }
}
resources:
  default:
    type: aws:rds:Instance
    properties:
      allocatedStorage: 50
      autoMinorVersionUpgrade: false # Custom for Oracle does not support minor version upgrades
      customIamInstanceProfile: AWSRDSCustomInstanceProfile
      backupRetentionPeriod: 7
      dbSubnetGroupName: ${dbSubnetGroupName}
      engine: ${["custom-oracle"].engine}
      engineVersion: ${["custom-oracle"].engineVersion}
      identifier: ee-instance-demo
      instanceClass: ${["custom-oracle"].instanceClass}
      kmsKeyId: ${byId.arn}
      licenseModel: ${["custom-oracle"].licenseModel}
      multiAz: false # Custom for Oracle does not support multi-az
      password: avoid-plaintext-passwords
      username: test
      storageEncrypted: true
  test-replica:
    type: aws:rds:Instance
    properties:
      replicateSourceDb: ${default.identifier}
      replicaMode: mounted
      autoMinorVersionUpgrade: false
      customIamInstanceProfile: AWSRDSCustomInstanceProfile
      backupRetentionPeriod: 7
      identifier: ee-instance-replica
      instanceClass: ${["custom-oracle"].instanceClass}
      kmsKeyId: ${byId.arn}
      multiAz: false # Custom for Oracle does not support multi-az
      skipFinalSnapshot: true
      storageEncrypted: true
variables:
  # Lookup the available instance classes for the custom engine for the region being operated in
  custom-oracle:
    fn::invoke:
      function: aws:rds:getOrderableDbInstance
      arguments:
        engine: custom-oracle-ee
        engineVersion: 19.c.ee.002
        licenseModel: bring-your-own-license
        storageType: gp3
        preferredInstanceClasses:
          - db.r5.xlarge
          - db.r5.2xlarge
          - db.r5.4xlarge
  # The RDS instance resource requires an ARN. Look up the ARN of the KMS key associated with the CEV.
  byId:
    fn::invoke:
      function: aws:kms:getKey
      arguments:
        keyId: example-ef278353ceba4a5a97de6784565b9f78

The customIamInstanceProfile grants the underlying EC2 instance permissions for RDS Custom operations. The engine and engineVersion specify the custom Oracle edition. The kmsKeyId encrypts storage; for RDS Custom, you must provide the KMS key ARN explicitly. The replica configuration uses replicateSourceDb to reference the primary instance identifier. The replicaMode property controls whether the replica operates in mounted mode (for backups) or open-read-only mode (for queries). Oracle replicas default to open-read-only unless you specify mounted.

Beyond these examples

These snippets focus on specific instance-level features: basic instance creation and storage configuration, Secrets Manager password management, and RDS Custom deployments and read replicas. They’re intentionally minimal rather than full database deployments.

The examples may reference pre-existing infrastructure such as VPC subnet groups and security groups, IAM roles for RDS Custom, Enhanced Monitoring, or Active Directory, KMS keys for encryption, and Secrets Manager for password management. They focus on configuring the instance rather than provisioning everything around it.

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

  • Backup configuration (backupRetentionPeriod, backupWindow)
  • High availability (multiAz, availabilityZone)
  • Network configuration (vpcSecurityGroupIds, publiclyAccessible)
  • Performance tuning (iops, storageThroughput, instanceClass selection)
  • Monitoring and logging (enabledCloudwatchLogsExports, performanceInsightsEnabled)
  • Maintenance windows and upgrade behavior

These omissions are intentional: the goal is to illustrate how each RDS feature is wired, not provide drop-in production 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
Why does using apply_immediately cause downtime?
Setting apply_immediately to true causes the server to reboot, resulting in a brief downtime. By default, changes are applied during the maintenance window to minimize disruption.
How do I upgrade to a major database engine version?
Set allow_major_version_upgrade to true when upgrading the major version of an engine. Without this flag, major version upgrades will fail.
What are the requirements for low-downtime updates using Blue/Green deployments?
Enable by setting blue_green_update.enabled to true. Requirements: MySQL, MariaDB, or PostgreSQL engine only; no replicas; and backup_retention_period must be greater than 0.
Storage & Autoscaling
How do I enable storage autoscaling?
Set max_allocated_storage to a value greater than or equal to allocated_storage. When autoscaling is enabled, Pulumi automatically ignores changes to allocated_storage as storage can dynamically scale.
What storage types are available and when should I use each?
Options are standard (magnetic), gp2 (general purpose SSD), gp3 (newer general purpose SSD), io1 (provisioned IOPS), or io2 (block express provisioned IOPS). The default is io1 if iops is specified, otherwise gp2.
When can I specify IOPS or storage throughput for gp3?
For gp3 storage, you cannot specify iops or storage_throughput if allocated_storage is below a per-engine threshold. See the RDS User Guide for specific thresholds.
Security & Password Management
How can I avoid storing passwords in plain-text state?
Set manage_master_user_password to true to store passwords in AWS Secrets Manager instead. To migrate an existing instance, set manage_master_user_password to true and remove the password attribute.
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 the correct KMS key initially.
Backups & Snapshots
When must backup_retention_period be greater than 0?
backup_retention_period must be greater than 0 if the database is used as a source for read replicas, uses low-downtime updates, or uses Blue/Green deployments. Valid range is 0-35 days, default is 0.
How do I prevent a final snapshot when deleting an instance?
Set skip_final_snapshot to true. If false (the default), you must provide final_snapshot_identifier for the snapshot name.
Read Replicas
How do I create a read replica?
Set replicate_source_db to the source database identifier (same region) or ARN (different region or with db_subnet_group_name). For encrypted cross-region replicas, also specify kms_key_id.
What happens if I remove replicate_source_db from a replica?
Removing the replicate_source_db attribute promotes the replica to a fully standalone database. This is a one-way operation.
Performance & Monitoring
How do I enable Performance Insights?
Set performance_insights_enabled to true. When specifying performance_insights_kms_key_id or performance_insights_retention_period, you must also set performance_insights_enabled to true.
What are the valid Performance Insights retention periods?
Valid values are 7 days (default), 731 days (2 years), or a multiple of 31 days.
Immutability & Engine-Specific Settings
What properties can't be changed after instance creation?
Key immutable properties include: availability_zone, backup_target, character_set_name, custom_iam_instance_profile, engine, kms_key_id, nchar_character_set_name, snapshot_identifier, storage_encrypted, timezone, and restore_to_point_in_time.
Which database engines support timezone configuration?
Only Microsoft SQL Server supports the timezone property, and it can only be set during instance creation.

Using a different cloud?

Explore database guides for other cloud providers: