Create and Configure Cloud SQL Instances

The gcp:sql/databaseInstance:DatabaseInstance resource, part of the Pulumi GCP provider, provisions a Cloud SQL database instance: its engine version, machine tier, region, and network configuration. This guide focuses on three capabilities: instance creation with database engine selection, network connectivity patterns (private IP, authorized networks, PSC), and performance tier features.

Cloud SQL instances don’t operate alone. Private IP connectivity requires VPC networks, global address reservations, and service networking connections. Authorized network configurations reference existing compute instances or on-premises IPs. The examples are intentionally small and demonstrate specific features. Combine them with your own VPC infrastructure, backup policies, and user management.

Create a basic PostgreSQL instance

Most deployments start by selecting a database engine, region, and machine tier.

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

const main = new gcp.sql.DatabaseInstance("main", {
    name: "main-instance",
    databaseVersion: "POSTGRES_15",
    region: "us-central1",
    settings: {
        tier: "db-f1-micro",
    },
});
import pulumi
import pulumi_gcp as gcp

main = gcp.sql.DatabaseInstance("main",
    name="main-instance",
    database_version="POSTGRES_15",
    region="us-central1",
    settings={
        "tier": "db-f1-micro",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/sql"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sql.NewDatabaseInstance(ctx, "main", &sql.DatabaseInstanceArgs{
			Name:            pulumi.String("main-instance"),
			DatabaseVersion: pulumi.String("POSTGRES_15"),
			Region:          pulumi.String("us-central1"),
			Settings: &sql.DatabaseInstanceSettingsArgs{
				Tier: pulumi.String("db-f1-micro"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var main = new Gcp.Sql.DatabaseInstance("main", new()
    {
        Name = "main-instance",
        DatabaseVersion = "POSTGRES_15",
        Region = "us-central1",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-f1-micro",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
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 main = new DatabaseInstance("main", DatabaseInstanceArgs.builder()
            .name("main-instance")
            .databaseVersion("POSTGRES_15")
            .region("us-central1")
            .settings(DatabaseInstanceSettingsArgs.builder()
                .tier("db-f1-micro")
                .build())
            .build());

    }
}
resources:
  main:
    type: gcp:sql:DatabaseInstance
    properties:
      name: main-instance
      databaseVersion: POSTGRES_15
      region: us-central1
      settings:
        tier: db-f1-micro

The databaseVersion property specifies the engine (PostgreSQL, MySQL, or SQL Server). The region determines where the instance runs. Inside settings, tier defines the machine type. This minimal configuration uses defaults for networking (public IP), backups (disabled), and availability (zonal).

Deploy with private IP and VPC peering

Applications in GCP often connect to databases through private networks rather than the public internet.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as random from "@pulumi/random";

const privateNetwork = new gcp.compute.Network("private_network", {name: "private-network"});
const privateIpAddress = new gcp.compute.GlobalAddress("private_ip_address", {
    name: "private-ip-address",
    purpose: "VPC_PEERING",
    addressType: "INTERNAL",
    prefixLength: 16,
    network: privateNetwork.id,
});
const privateVpcConnection = new gcp.servicenetworking.Connection("private_vpc_connection", {
    network: privateNetwork.id,
    service: "servicenetworking.googleapis.com",
    reservedPeeringRanges: [privateIpAddress.name],
});
const dbNameSuffix = new random.RandomId("db_name_suffix", {byteLength: 4});
const instance = new gcp.sql.DatabaseInstance("instance", {
    name: pulumi.interpolate`private-instance-${dbNameSuffix.hex}`,
    region: "us-central1",
    databaseVersion: "MYSQL_5_7",
    settings: {
        tier: "db-f1-micro",
        ipConfiguration: {
            ipv4Enabled: false,
            privateNetwork: privateNetwork.selfLink,
            enablePrivatePathForGoogleCloudServices: true,
        },
    },
}, {
    dependsOn: [privateVpcConnection],
});
import pulumi
import pulumi_gcp as gcp
import pulumi_random as random

private_network = gcp.compute.Network("private_network", name="private-network")
private_ip_address = gcp.compute.GlobalAddress("private_ip_address",
    name="private-ip-address",
    purpose="VPC_PEERING",
    address_type="INTERNAL",
    prefix_length=16,
    network=private_network.id)
private_vpc_connection = gcp.servicenetworking.Connection("private_vpc_connection",
    network=private_network.id,
    service="servicenetworking.googleapis.com",
    reserved_peering_ranges=[private_ip_address.name])
db_name_suffix = random.RandomId("db_name_suffix", byte_length=4)
instance = gcp.sql.DatabaseInstance("instance",
    name=db_name_suffix.hex.apply(lambda hex: f"private-instance-{hex}"),
    region="us-central1",
    database_version="MYSQL_5_7",
    settings={
        "tier": "db-f1-micro",
        "ip_configuration": {
            "ipv4_enabled": False,
            "private_network": private_network.self_link,
            "enable_private_path_for_google_cloud_services": True,
        },
    },
    opts = pulumi.ResourceOptions(depends_on=[private_vpc_connection]))
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/servicenetworking"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/sql"
	"github.com/pulumi/pulumi-random/sdk/v4/go/random"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		privateNetwork, err := compute.NewNetwork(ctx, "private_network", &compute.NetworkArgs{
			Name: pulumi.String("private-network"),
		})
		if err != nil {
			return err
		}
		privateIpAddress, err := compute.NewGlobalAddress(ctx, "private_ip_address", &compute.GlobalAddressArgs{
			Name:         pulumi.String("private-ip-address"),
			Purpose:      pulumi.String("VPC_PEERING"),
			AddressType:  pulumi.String("INTERNAL"),
			PrefixLength: pulumi.Int(16),
			Network:      privateNetwork.ID(),
		})
		if err != nil {
			return err
		}
		privateVpcConnection, err := servicenetworking.NewConnection(ctx, "private_vpc_connection", &servicenetworking.ConnectionArgs{
			Network: privateNetwork.ID(),
			Service: pulumi.String("servicenetworking.googleapis.com"),
			ReservedPeeringRanges: pulumi.StringArray{
				privateIpAddress.Name,
			},
		})
		if err != nil {
			return err
		}
		dbNameSuffix, err := random.NewRandomId(ctx, "db_name_suffix", &random.RandomIdArgs{
			ByteLength: pulumi.Int(4),
		})
		if err != nil {
			return err
		}
		_, err = sql.NewDatabaseInstance(ctx, "instance", &sql.DatabaseInstanceArgs{
			Name: dbNameSuffix.Hex.ApplyT(func(hex string) (string, error) {
				return fmt.Sprintf("private-instance-%v", hex), nil
			}).(pulumi.StringOutput),
			Region:          pulumi.String("us-central1"),
			DatabaseVersion: pulumi.String("MYSQL_5_7"),
			Settings: &sql.DatabaseInstanceSettingsArgs{
				Tier: pulumi.String("db-f1-micro"),
				IpConfiguration: &sql.DatabaseInstanceSettingsIpConfigurationArgs{
					Ipv4Enabled:                             pulumi.Bool(false),
					PrivateNetwork:                          privateNetwork.SelfLink,
					EnablePrivatePathForGoogleCloudServices: pulumi.Bool(true),
				},
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			privateVpcConnection,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Random = Pulumi.Random;

return await Deployment.RunAsync(() => 
{
    var privateNetwork = new Gcp.Compute.Network("private_network", new()
    {
        Name = "private-network",
    });

    var privateIpAddress = new Gcp.Compute.GlobalAddress("private_ip_address", new()
    {
        Name = "private-ip-address",
        Purpose = "VPC_PEERING",
        AddressType = "INTERNAL",
        PrefixLength = 16,
        Network = privateNetwork.Id,
    });

    var privateVpcConnection = new Gcp.ServiceNetworking.Connection("private_vpc_connection", new()
    {
        Network = privateNetwork.Id,
        Service = "servicenetworking.googleapis.com",
        ReservedPeeringRanges = new[]
        {
            privateIpAddress.Name,
        },
    });

    var dbNameSuffix = new Random.RandomId("db_name_suffix", new()
    {
        ByteLength = 4,
    });

    var instance = new Gcp.Sql.DatabaseInstance("instance", new()
    {
        Name = dbNameSuffix.Hex.Apply(hex => $"private-instance-{hex}"),
        Region = "us-central1",
        DatabaseVersion = "MYSQL_5_7",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-f1-micro",
            IpConfiguration = new Gcp.Sql.Inputs.DatabaseInstanceSettingsIpConfigurationArgs
            {
                Ipv4Enabled = false,
                PrivateNetwork = privateNetwork.SelfLink,
                EnablePrivatePathForGoogleCloudServices = true,
            },
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            privateVpcConnection,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.GlobalAddress;
import com.pulumi.gcp.compute.GlobalAddressArgs;
import com.pulumi.gcp.servicenetworking.Connection;
import com.pulumi.gcp.servicenetworking.ConnectionArgs;
import com.pulumi.random.RandomId;
import com.pulumi.random.RandomIdArgs;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsIpConfigurationArgs;
import com.pulumi.resources.CustomResourceOptions;
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 privateNetwork = new Network("privateNetwork", NetworkArgs.builder()
            .name("private-network")
            .build());

        var privateIpAddress = new GlobalAddress("privateIpAddress", GlobalAddressArgs.builder()
            .name("private-ip-address")
            .purpose("VPC_PEERING")
            .addressType("INTERNAL")
            .prefixLength(16)
            .network(privateNetwork.id())
            .build());

        var privateVpcConnection = new Connection("privateVpcConnection", ConnectionArgs.builder()
            .network(privateNetwork.id())
            .service("servicenetworking.googleapis.com")
            .reservedPeeringRanges(privateIpAddress.name())
            .build());

        var dbNameSuffix = new RandomId("dbNameSuffix", RandomIdArgs.builder()
            .byteLength(4)
            .build());

        var instance = new DatabaseInstance("instance", DatabaseInstanceArgs.builder()
            .name(dbNameSuffix.hex().applyValue(_hex -> String.format("private-instance-%s", _hex)))
            .region("us-central1")
            .databaseVersion("MYSQL_5_7")
            .settings(DatabaseInstanceSettingsArgs.builder()
                .tier("db-f1-micro")
                .ipConfiguration(DatabaseInstanceSettingsIpConfigurationArgs.builder()
                    .ipv4Enabled(false)
                    .privateNetwork(privateNetwork.selfLink())
                    .enablePrivatePathForGoogleCloudServices(true)
                    .build())
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(privateVpcConnection)
                .build());

    }
}
resources:
  privateNetwork:
    type: gcp:compute:Network
    name: private_network
    properties:
      name: private-network
  privateIpAddress:
    type: gcp:compute:GlobalAddress
    name: private_ip_address
    properties:
      name: private-ip-address
      purpose: VPC_PEERING
      addressType: INTERNAL
      prefixLength: 16
      network: ${privateNetwork.id}
  privateVpcConnection:
    type: gcp:servicenetworking:Connection
    name: private_vpc_connection
    properties:
      network: ${privateNetwork.id}
      service: servicenetworking.googleapis.com
      reservedPeeringRanges:
        - ${privateIpAddress.name}
  dbNameSuffix:
    type: random:RandomId
    name: db_name_suffix
    properties:
      byteLength: 4
  instance:
    type: gcp:sql:DatabaseInstance
    properties:
      name: private-instance-${dbNameSuffix.hex}
      region: us-central1
      databaseVersion: MYSQL_5_7
      settings:
        tier: db-f1-micro
        ipConfiguration:
          ipv4Enabled: false
          privateNetwork: ${privateNetwork.selfLink}
          enablePrivatePathForGoogleCloudServices: true
    options:
      dependsOn:
        - ${privateVpcConnection}

The ipConfiguration block disables public IP (ipv4Enabled: false) and connects the instance to a VPC via privateNetwork. This requires a VPC network, a reserved global address range, and a service networking connection. The dependsOn reference is explicit because Cloud SQL doesn’t automatically detect the connection dependency.

Restrict access to specific IP addresses

Production databases often limit access to known client IPs from on-premises networks or specific instances.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as random from "@pulumi/random";

const apps: gcp.compute.Instance[] = [];
for (const range = {value: 0}; range.value < 8; range.value++) {
    apps.push(new gcp.compute.Instance(`apps-${range.value}`, {
        networkInterfaces: [{
            accessConfigs: [{}],
            network: "default",
        }],
        name: `apps-${range.value + 1}`,
        machineType: "f1-micro",
        bootDisk: {
            initializeParams: {
                image: "ubuntu-os-cloud/ubuntu-1804-lts",
            },
        },
    }));
}
const dbNameSuffix = new random.RandomId("db_name_suffix", {byteLength: 4});
const onprem = [
    "192.168.1.2",
    "192.168.2.3",
];
const postgres = new gcp.sql.DatabaseInstance("postgres", {
    name: pulumi.interpolate`postgres-instance-${dbNameSuffix.hex}`,
    databaseVersion: "POSTGRES_15",
    settings: {
        tier: "db-f1-micro",
        ipConfiguration: {
            authorizedNetworks: Object.entries(apps).map(([k, v]) => ({key: k, value: v})).apply(entries => entries.map(entry => ({
                name: entry.value.name,
                value: entry.value.networkInterface[0].accessConfig[0].natIp,
            }))),
            authorizedNetworks: onprem.map((v, k) => ({key: k, value: v})).map(entry2 => ({
                name: `onprem-${entry2.key}`,
                value: entry2.value,
            })),
        },
    },
});
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Random = Pulumi.Random;

return await Deployment.RunAsync(() => 
{
    var apps = new List<Gcp.Compute.Instance>();
    for (var rangeIndex = 0; rangeIndex < 8; rangeIndex++)
    {
        var range = new { Value = rangeIndex };
        apps.Add(new Gcp.Compute.Instance($"apps-{range.Value}", new()
        {
            NetworkInterfaces = new[]
            {
                new Gcp.Compute.Inputs.InstanceNetworkInterfaceArgs
                {
                    AccessConfigs = new[]
                    {
                        null,
                    },
                    Network = "default",
                },
            },
            Name = $"apps-{range.Value + 1}",
            MachineType = "f1-micro",
            BootDisk = new Gcp.Compute.Inputs.InstanceBootDiskArgs
            {
                InitializeParams = new Gcp.Compute.Inputs.InstanceBootDiskInitializeParamsArgs
                {
                    Image = "ubuntu-os-cloud/ubuntu-1804-lts",
                },
            },
        }));
    }
    var dbNameSuffix = new Random.RandomId("db_name_suffix", new()
    {
        ByteLength = 4,
    });

    var onprem = new[]
    {
        "192.168.1.2",
        "192.168.2.3",
    };

    var postgres = new Gcp.Sql.DatabaseInstance("postgres", new()
    {
        Name = dbNameSuffix.Hex.Apply(hex => $"postgres-instance-{hex}"),
        DatabaseVersion = "POSTGRES_15",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-f1-micro",
            IpConfiguration = new Gcp.Sql.Inputs.DatabaseInstanceSettingsIpConfigurationArgs
            {
                AuthorizedNetworks = .Apply(entries => entries.Select(entry => 
                {
                    return 
                    {
                        { "name", entry.Value.Name },
                        { "value", entry.Value.NetworkInterface[0].AccessConfig[0].NatIp },
                    };
                }).ToList()),
                AuthorizedNetworks = onprem.Select((v, k) => new { Key = k, Value = v }).Select(entry2 => 
                {
                    return new Gcp.Sql.Inputs.DatabaseInstanceSettingsIpConfigurationAuthorizedNetworkArgs
                    {
                        Name = $"onprem-{entry2.Key}",
                        Value = entry2.Value,
                    };
                }).ToList(),
            },
        },
    });

});

When using public IP connectivity, authorizedNetworks controls which IPs can connect. Each entry specifies a name and IP address or CIDR range. The example shows two patterns: dynamically collecting NAT IPs from compute instances, and statically listing on-premises addresses.

Enable data cache for ENTERPRISE_PLUS tier

High-performance workloads can leverage in-memory caching in ENTERPRISE_PLUS edition instances.

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

const main = new gcp.sql.DatabaseInstance("main", {
    name: "enterprise-plus-main-instance",
    databaseVersion: "MYSQL_8_0_31",
    settings: {
        tier: "db-perf-optimized-N-2",
        edition: "ENTERPRISE_PLUS",
        dataCacheConfig: {
            dataCacheEnabled: true,
        },
    },
});
import pulumi
import pulumi_gcp as gcp

main = gcp.sql.DatabaseInstance("main",
    name="enterprise-plus-main-instance",
    database_version="MYSQL_8_0_31",
    settings={
        "tier": "db-perf-optimized-N-2",
        "edition": "ENTERPRISE_PLUS",
        "data_cache_config": {
            "data_cache_enabled": True,
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/sql"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sql.NewDatabaseInstance(ctx, "main", &sql.DatabaseInstanceArgs{
			Name:            pulumi.String("enterprise-plus-main-instance"),
			DatabaseVersion: pulumi.String("MYSQL_8_0_31"),
			Settings: &sql.DatabaseInstanceSettingsArgs{
				Tier:    pulumi.String("db-perf-optimized-N-2"),
				Edition: pulumi.String("ENTERPRISE_PLUS"),
				DataCacheConfig: &sql.DatabaseInstanceSettingsDataCacheConfigArgs{
					DataCacheEnabled: pulumi.Bool(true),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var main = new Gcp.Sql.DatabaseInstance("main", new()
    {
        Name = "enterprise-plus-main-instance",
        DatabaseVersion = "MYSQL_8_0_31",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-perf-optimized-N-2",
            Edition = "ENTERPRISE_PLUS",
            DataCacheConfig = new Gcp.Sql.Inputs.DatabaseInstanceSettingsDataCacheConfigArgs
            {
                DataCacheEnabled = true,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsDataCacheConfigArgs;
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 main = new DatabaseInstance("main", DatabaseInstanceArgs.builder()
            .name("enterprise-plus-main-instance")
            .databaseVersion("MYSQL_8_0_31")
            .settings(DatabaseInstanceSettingsArgs.builder()
                .tier("db-perf-optimized-N-2")
                .edition("ENTERPRISE_PLUS")
                .dataCacheConfig(DatabaseInstanceSettingsDataCacheConfigArgs.builder()
                    .dataCacheEnabled(true)
                    .build())
                .build())
            .build());

    }
}
resources:
  main:
    type: gcp:sql:DatabaseInstance
    properties:
      name: enterprise-plus-main-instance
      databaseVersion: MYSQL_8_0_31
      settings:
        tier: db-perf-optimized-N-2
        edition: ENTERPRISE_PLUS
        dataCacheConfig:
          dataCacheEnabled: true

The edition property selects ENTERPRISE_PLUS, which unlocks features like data caching. Inside settings, dataCacheConfig enables the cache. This requires a performance-optimized tier (db-perf-optimized-N-2). Data caching improves query performance by keeping frequently accessed data in memory.

Configure Private Service Connect for consumer projects

Organizations with multiple projects can use Private Service Connect (PSC) to share database access without VPC peering.

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

const main = new gcp.sql.DatabaseInstance("main", {
    name: "psc-enabled-main-instance",
    databaseVersion: "MYSQL_8_0",
    settings: {
        tier: "db-f1-micro",
        ipConfiguration: {
            pscConfigs: [{
                pscEnabled: true,
                allowedConsumerProjects: ["allowed-consumer-project-name"],
            }],
            ipv4Enabled: false,
        },
        backupConfiguration: {
            enabled: true,
            binaryLogEnabled: true,
        },
        availabilityType: "REGIONAL",
    },
});
import pulumi
import pulumi_gcp as gcp

main = gcp.sql.DatabaseInstance("main",
    name="psc-enabled-main-instance",
    database_version="MYSQL_8_0",
    settings={
        "tier": "db-f1-micro",
        "ip_configuration": {
            "psc_configs": [{
                "psc_enabled": True,
                "allowed_consumer_projects": ["allowed-consumer-project-name"],
            }],
            "ipv4_enabled": False,
        },
        "backup_configuration": {
            "enabled": True,
            "binary_log_enabled": True,
        },
        "availability_type": "REGIONAL",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/sql"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sql.NewDatabaseInstance(ctx, "main", &sql.DatabaseInstanceArgs{
			Name:            pulumi.String("psc-enabled-main-instance"),
			DatabaseVersion: pulumi.String("MYSQL_8_0"),
			Settings: &sql.DatabaseInstanceSettingsArgs{
				Tier: pulumi.String("db-f1-micro"),
				IpConfiguration: &sql.DatabaseInstanceSettingsIpConfigurationArgs{
					PscConfigs: sql.DatabaseInstanceSettingsIpConfigurationPscConfigArray{
						&sql.DatabaseInstanceSettingsIpConfigurationPscConfigArgs{
							PscEnabled: pulumi.Bool(true),
							AllowedConsumerProjects: pulumi.StringArray{
								pulumi.String("allowed-consumer-project-name"),
							},
						},
					},
					Ipv4Enabled: pulumi.Bool(false),
				},
				BackupConfiguration: &sql.DatabaseInstanceSettingsBackupConfigurationArgs{
					Enabled:          pulumi.Bool(true),
					BinaryLogEnabled: pulumi.Bool(true),
				},
				AvailabilityType: pulumi.String("REGIONAL"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var main = new Gcp.Sql.DatabaseInstance("main", new()
    {
        Name = "psc-enabled-main-instance",
        DatabaseVersion = "MYSQL_8_0",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-f1-micro",
            IpConfiguration = new Gcp.Sql.Inputs.DatabaseInstanceSettingsIpConfigurationArgs
            {
                PscConfigs = new[]
                {
                    new Gcp.Sql.Inputs.DatabaseInstanceSettingsIpConfigurationPscConfigArgs
                    {
                        PscEnabled = true,
                        AllowedConsumerProjects = new[]
                        {
                            "allowed-consumer-project-name",
                        },
                    },
                },
                Ipv4Enabled = false,
            },
            BackupConfiguration = new Gcp.Sql.Inputs.DatabaseInstanceSettingsBackupConfigurationArgs
            {
                Enabled = true,
                BinaryLogEnabled = true,
            },
            AvailabilityType = "REGIONAL",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsIpConfigurationArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsBackupConfigurationArgs;
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 main = new DatabaseInstance("main", DatabaseInstanceArgs.builder()
            .name("psc-enabled-main-instance")
            .databaseVersion("MYSQL_8_0")
            .settings(DatabaseInstanceSettingsArgs.builder()
                .tier("db-f1-micro")
                .ipConfiguration(DatabaseInstanceSettingsIpConfigurationArgs.builder()
                    .pscConfigs(DatabaseInstanceSettingsIpConfigurationPscConfigArgs.builder()
                        .pscEnabled(true)
                        .allowedConsumerProjects("allowed-consumer-project-name")
                        .build())
                    .ipv4Enabled(false)
                    .build())
                .backupConfiguration(DatabaseInstanceSettingsBackupConfigurationArgs.builder()
                    .enabled(true)
                    .binaryLogEnabled(true)
                    .build())
                .availabilityType("REGIONAL")
                .build())
            .build());

    }
}
resources:
  main:
    type: gcp:sql:DatabaseInstance
    properties:
      name: psc-enabled-main-instance
      databaseVersion: MYSQL_8_0
      settings:
        tier: db-f1-micro
        ipConfiguration:
          pscConfigs:
            - pscEnabled: true
              allowedConsumerProjects:
                - allowed-consumer-project-name
          ipv4Enabled: false
        backupConfiguration:
          enabled: true
          binaryLogEnabled: true
        availabilityType: REGIONAL

PSC configuration lives in ipConfiguration.pscConfigs. Set pscEnabled to true and list allowedConsumerProjects that can connect. PSC requires regional availability (availabilityType: REGIONAL), disabled public IP (ipv4Enabled: false), and enabled backups with binary logging. Consumer projects connect via service attachments rather than direct IP addresses.

Beyond These Examples

These snippets focus on specific instance-level features: basic provisioning (database version, region, tier), network connectivity (private IP, authorized networks, PSC), and performance features (data cache, connection pooling). They’re intentionally minimal rather than full database deployments.

The examples may reference pre-existing infrastructure such as VPC networks and global address reservations for private IP, service networking connections for VPC peering, and compute instances for authorized network examples. They focus on configuring the instance rather than provisioning everything around it.

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

  • Backup and recovery configuration (backupConfiguration, pointInTimeRecovery)
  • High availability settings (availabilityType for most examples)
  • Maintenance windows and update timing
  • Encryption keys (encryptionKeyName for CMEK)
  • Read replicas and replication configuration
  • User management and root password setup

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

Frequently Asked Questions

Security & Access
Why was the default root user deleted from my instance?
Second-generation Cloud SQL instances include a default ‘root’@’%’ user with no password. This user is automatically deleted by Pulumi on instance creation for security. Use gcp.sql.User to define a custom user with a restricted host and strong password.
How do I delete my Cloud SQL instance?
Set deletionProtection to false and run pulumi update to write the field to state, then run pulumi destroy. Deletion protection defaults to true to prevent accidental deletions.
What manual steps are required to enable CMEK disk encryption?
Set encryptionKeyName to the full path of your encryption key. Before this works, you must manually create a special service account, grant it the ‘Cloud KMS CryptoKey Encrypter/Decrypter’ role on your key, and the key must be in the same region as your instance. See the GCP documentation for CMEK configuration steps.
Networking & Connectivity
Why do I need dependsOn for private IP instances?
The gcp.sql.DatabaseInstance doesn’t interpolate values from gcp.servicenetworking.Connection, so you must explicitly add dependsOn to ensure VPC peering is ready before the instance is created. Without this, the instance may fail to create or have connectivity issues.
How do I enable Private Service Connect (PSC) for my instance?
Configure settings.ipConfiguration.pscConfigs with pscEnabled set to true and specify allowedConsumerProjects. You must also disable public IP (ipv4Enabled to false), enable backups (backupConfiguration.enabled and binaryLogEnabled for MySQL), and set availabilityType to ‘REGIONAL’.
Replication & Disaster Recovery
What happens if I don't follow the switchover procedure correctly?
Failure to follow switchover steps can lead to data loss. The switchover procedure involves changing instanceType, masterInstanceName, replicaNames, and other properties on both the primary and replica in a specific sequence.
How do I verify my switchover configuration before applying it?
Run pulumi preview and verify that it outputs ‘0 to add, 0 to destroy’, no resources say ‘must be replaced’, every resource says ‘will be updated in-place’, and only the 2 instances involved in switchover have planned changes. Use deletionProtection as an additional safety measure.
What's required to set up a read replica?
Set masterInstanceName to the name of the existing master instance. The master must have binaryLogEnabled set and existing backups configured.
Instance Lifecycle & Immutability
What properties can't be changed after instance creation?
The following properties are immutable: name, encryptionKeyName, region, and project. Changing these requires replacing the instance.
Can I reuse an instance name immediately after deletion?
No, instance names can’t be reused for up to one week after deletion. If you need to recreate an instance quickly, use a different name.
What happens when I import an existing Cloud SQL instance?
After importing, double-check that your config has all the fields set that you expect. Just seeing no diff isn’t sufficient to know that your config could reproduce the imported resource.
Maintenance & Updates
Does updating maintenanceVersion cause downtime?
Yes, updating maintenanceVersion will cause an instance restart. The property can’t be set during creation and setting an older value than the current one will be ignored.
Should I use restoreBackupContext to restore from backups?
No, restoring from a backup is an imperative action and not recommended via Pulumi. Adding or modifying restoreBackupContext during resource creation or update will trigger the restore action. Use the GCP Console or gcloud CLI for restore operations instead.

Ready to get started?

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

Create free account