Create GCP Cloud SQL Users

The gcp:sql/user:User resource, part of the Pulumi GCP provider, defines database users on Cloud SQL instances: their authentication method, privileges, and connection restrictions. This guide focuses on three capabilities: password-based authentication, database role assignment, and Cloud IAM authentication for users, service accounts, and groups.

Database users belong to Cloud SQL instances and may reference IAM identities or require specific database flags for IAM authentication. The examples are intentionally small. Combine them with your own instance configuration and access policies.

Create a user with password authentication

Most deployments start with traditional username/password authentication, where applications connect using credentials stored in configuration or secrets.

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

const dbNameSuffix = new random.index.Id("db_name_suffix", {byteLength: 4});
const main = new gcp.sql.DatabaseInstance("main", {
    name: `main-instance-${dbNameSuffix.hex}`,
    databaseVersion: "MYSQL_5_7",
    settings: {
        tier: "db-f1-micro",
    },
});
const users = new gcp.sql.User("users", {
    name: "me",
    instance: main.name,
    host: "me.com",
    password: "changeme",
});
import pulumi
import pulumi_gcp as gcp
import pulumi_random as random

db_name_suffix = random.index.Id("db_name_suffix", byte_length=4)
main = gcp.sql.DatabaseInstance("main",
    name=f"main-instance-{db_name_suffix['hex']}",
    database_version="MYSQL_5_7",
    settings={
        "tier": "db-f1-micro",
    })
users = gcp.sql.User("users",
    name="me",
    instance=main.name,
    host="me.com",
    password="changeme")
package main

import (
	"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 {
		dbNameSuffix, err := random.NewId(ctx, "db_name_suffix", &random.IdArgs{
			ByteLength: 4,
		})
		if err != nil {
			return err
		}
		main, err := sql.NewDatabaseInstance(ctx, "main", &sql.DatabaseInstanceArgs{
			Name:            pulumi.Sprintf("main-instance-%v", dbNameSuffix.Hex),
			DatabaseVersion: pulumi.String("MYSQL_5_7"),
			Settings: &sql.DatabaseInstanceSettingsArgs{
				Tier: pulumi.String("db-f1-micro"),
			},
		})
		if err != nil {
			return err
		}
		_, err = sql.NewUser(ctx, "users", &sql.UserArgs{
			Name:     pulumi.String("me"),
			Instance: main.Name,
			Host:     pulumi.String("me.com"),
			Password: pulumi.String("changeme"),
		})
		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 dbNameSuffix = new Random.Index.Id("db_name_suffix", new()
    {
        ByteLength = 4,
    });

    var main = new Gcp.Sql.DatabaseInstance("main", new()
    {
        Name = $"main-instance-{dbNameSuffix.Hex}",
        DatabaseVersion = "MYSQL_5_7",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-f1-micro",
        },
    });

    var users = new Gcp.Sql.User("users", new()
    {
        Name = "me",
        Instance = main.Name,
        Host = "me.com",
        Password = "changeme",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.random.Id;
import com.pulumi.random.IdArgs;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
import com.pulumi.gcp.sql.User;
import com.pulumi.gcp.sql.UserArgs;
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 dbNameSuffix = new Id("dbNameSuffix", IdArgs.builder()
            .byteLength(4)
            .build());

        var main = new DatabaseInstance("main", DatabaseInstanceArgs.builder()
            .name(String.format("main-instance-%s", dbNameSuffix.hex()))
            .databaseVersion("MYSQL_5_7")
            .settings(DatabaseInstanceSettingsArgs.builder()
                .tier("db-f1-micro")
                .build())
            .build());

        var users = new User("users", UserArgs.builder()
            .name("me")
            .instance(main.name())
            .host("me.com")
            .password("changeme")
            .build());

    }
}
resources:
  dbNameSuffix:
    type: random:Id
    name: db_name_suffix
    properties:
      byteLength: 4
  main:
    type: gcp:sql:DatabaseInstance
    properties:
      name: main-instance-${dbNameSuffix.hex}
      databaseVersion: MYSQL_5_7
      settings:
        tier: db-f1-micro
  users:
    type: gcp:sql:User
    properties:
      name: me
      instance: ${main.name}
      host: me.com
      password: changeme

The name property sets the username, while password provides the credential. The host property restricts which IP addresses can connect (MySQL only; omit for PostgreSQL). The instance property links the user to a specific Cloud SQL instance.

Assign database roles for privilege management

PostgreSQL and MySQL 8+ support database roles that grant specific privileges without requiring manual GRANT statements after user creation.

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

const dbNameSuffix = new random.index.Id("db_name_suffix", {byteLength: 4});
const main = new gcp.sql.DatabaseInstance("main", {
    name: `main-instance-${dbNameSuffix.hex}`,
    databaseVersion: "POSTGRES_15",
    settings: {
        tier: "db-f1-micro",
    },
});
const users = new gcp.sql.User("users", {
    name: "me",
    instance: main.name,
    host: "me.com",
    password: "changeme",
    databaseRoles: ["cloudsqlsuperuser"],
});
import pulumi
import pulumi_gcp as gcp
import pulumi_random as random

db_name_suffix = random.index.Id("db_name_suffix", byte_length=4)
main = gcp.sql.DatabaseInstance("main",
    name=f"main-instance-{db_name_suffix['hex']}",
    database_version="POSTGRES_15",
    settings={
        "tier": "db-f1-micro",
    })
users = gcp.sql.User("users",
    name="me",
    instance=main.name,
    host="me.com",
    password="changeme",
    database_roles=["cloudsqlsuperuser"])
package main

import (
	"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 {
		dbNameSuffix, err := random.NewId(ctx, "db_name_suffix", &random.IdArgs{
			ByteLength: 4,
		})
		if err != nil {
			return err
		}
		main, err := sql.NewDatabaseInstance(ctx, "main", &sql.DatabaseInstanceArgs{
			Name:            pulumi.Sprintf("main-instance-%v", dbNameSuffix.Hex),
			DatabaseVersion: pulumi.String("POSTGRES_15"),
			Settings: &sql.DatabaseInstanceSettingsArgs{
				Tier: pulumi.String("db-f1-micro"),
			},
		})
		if err != nil {
			return err
		}
		_, err = sql.NewUser(ctx, "users", &sql.UserArgs{
			Name:     pulumi.String("me"),
			Instance: main.Name,
			Host:     pulumi.String("me.com"),
			Password: pulumi.String("changeme"),
			DatabaseRoles: pulumi.StringArray{
				pulumi.String("cloudsqlsuperuser"),
			},
		})
		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 dbNameSuffix = new Random.Index.Id("db_name_suffix", new()
    {
        ByteLength = 4,
    });

    var main = new Gcp.Sql.DatabaseInstance("main", new()
    {
        Name = $"main-instance-{dbNameSuffix.Hex}",
        DatabaseVersion = "POSTGRES_15",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-f1-micro",
        },
    });

    var users = new Gcp.Sql.User("users", new()
    {
        Name = "me",
        Instance = main.Name,
        Host = "me.com",
        Password = "changeme",
        DatabaseRoles = new[]
        {
            "cloudsqlsuperuser",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.random.Id;
import com.pulumi.random.IdArgs;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
import com.pulumi.gcp.sql.User;
import com.pulumi.gcp.sql.UserArgs;
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 dbNameSuffix = new Id("dbNameSuffix", IdArgs.builder()
            .byteLength(4)
            .build());

        var main = new DatabaseInstance("main", DatabaseInstanceArgs.builder()
            .name(String.format("main-instance-%s", dbNameSuffix.hex()))
            .databaseVersion("POSTGRES_15")
            .settings(DatabaseInstanceSettingsArgs.builder()
                .tier("db-f1-micro")
                .build())
            .build());

        var users = new User("users", UserArgs.builder()
            .name("me")
            .instance(main.name())
            .host("me.com")
            .password("changeme")
            .databaseRoles("cloudsqlsuperuser")
            .build());

    }
}
resources:
  dbNameSuffix:
    type: random:Id
    name: db_name_suffix
    properties:
      byteLength: 4
  main:
    type: gcp:sql:DatabaseInstance
    properties:
      name: main-instance-${dbNameSuffix.hex}
      databaseVersion: POSTGRES_15
      settings:
        tier: db-f1-micro
  users:
    type: gcp:sql:User
    properties:
      name: me
      instance: ${main.name}
      host: me.com
      password: changeme
      databaseRoles:
        - cloudsqlsuperuser

The databaseRoles property assigns predefined roles like cloudsqlsuperuser or custom roles you’ve created in the database. This extends basic password authentication with role-based access control, eliminating the need to run separate GRANT commands.

Authenticate with Cloud IAM identities

Cloud SQL IAM authentication eliminates password management by letting users and service accounts authenticate using their Google Cloud identities.

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

const dbNameSuffix = new random.index.Id("db_name_suffix", {byteLength: 4});
const main = new gcp.sql.DatabaseInstance("main", {
    name: `main-instance-${dbNameSuffix.hex}`,
    databaseVersion: "POSTGRES_15",
    settings: {
        tier: "db-f1-micro",
        databaseFlags: [{
            name: "cloudsql.iam_authentication",
            value: "on",
        }],
    },
});
const iamUser = new gcp.sql.User("iam_user", {
    name: "me@example.com",
    instance: main.name,
    type: "CLOUD_IAM_USER",
});
const iamServiceAccountUser = new gcp.sql.User("iam_service_account_user", {
    name: std.trimsuffix({
        input: serviceAccount.email,
        suffix: ".gserviceaccount.com",
    }).then(invoke => invoke.result),
    instance: main.name,
    type: "CLOUD_IAM_SERVICE_ACCOUNT",
});
import pulumi
import pulumi_gcp as gcp
import pulumi_random as random
import pulumi_std as std

db_name_suffix = random.index.Id("db_name_suffix", byte_length=4)
main = gcp.sql.DatabaseInstance("main",
    name=f"main-instance-{db_name_suffix['hex']}",
    database_version="POSTGRES_15",
    settings={
        "tier": "db-f1-micro",
        "database_flags": [{
            "name": "cloudsql.iam_authentication",
            "value": "on",
        }],
    })
iam_user = gcp.sql.User("iam_user",
    name="me@example.com",
    instance=main.name,
    type="CLOUD_IAM_USER")
iam_service_account_user = gcp.sql.User("iam_service_account_user",
    name=std.trimsuffix(input=service_account["email"],
        suffix=".gserviceaccount.com").result,
    instance=main.name,
    type="CLOUD_IAM_SERVICE_ACCOUNT")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		dbNameSuffix, err := random.NewId(ctx, "db_name_suffix", &random.IdArgs{
			ByteLength: 4,
		})
		if err != nil {
			return err
		}
		main, err := sql.NewDatabaseInstance(ctx, "main", &sql.DatabaseInstanceArgs{
			Name:            pulumi.Sprintf("main-instance-%v", dbNameSuffix.Hex),
			DatabaseVersion: pulumi.String("POSTGRES_15"),
			Settings: &sql.DatabaseInstanceSettingsArgs{
				Tier: pulumi.String("db-f1-micro"),
				DatabaseFlags: sql.DatabaseInstanceSettingsDatabaseFlagArray{
					&sql.DatabaseInstanceSettingsDatabaseFlagArgs{
						Name:  pulumi.String("cloudsql.iam_authentication"),
						Value: pulumi.String("on"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		_, err = sql.NewUser(ctx, "iam_user", &sql.UserArgs{
			Name:     pulumi.String("me@example.com"),
			Instance: main.Name,
			Type:     pulumi.String("CLOUD_IAM_USER"),
		})
		if err != nil {
			return err
		}
		invokeTrimsuffix, err := std.Trimsuffix(ctx, &std.TrimsuffixArgs{
			Input:  serviceAccount.Email,
			Suffix: ".gserviceaccount.com",
		}, nil)
		if err != nil {
			return err
		}
		_, err = sql.NewUser(ctx, "iam_service_account_user", &sql.UserArgs{
			Name:     pulumi.String(invokeTrimsuffix.Result),
			Instance: main.Name,
			Type:     pulumi.String("CLOUD_IAM_SERVICE_ACCOUNT"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Random = Pulumi.Random;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var dbNameSuffix = new Random.Index.Id("db_name_suffix", new()
    {
        ByteLength = 4,
    });

    var main = new Gcp.Sql.DatabaseInstance("main", new()
    {
        Name = $"main-instance-{dbNameSuffix.Hex}",
        DatabaseVersion = "POSTGRES_15",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-f1-micro",
            DatabaseFlags = new[]
            {
                new Gcp.Sql.Inputs.DatabaseInstanceSettingsDatabaseFlagArgs
                {
                    Name = "cloudsql.iam_authentication",
                    Value = "on",
                },
            },
        },
    });

    var iamUser = new Gcp.Sql.User("iam_user", new()
    {
        Name = "me@example.com",
        Instance = main.Name,
        Type = "CLOUD_IAM_USER",
    });

    var iamServiceAccountUser = new Gcp.Sql.User("iam_service_account_user", new()
    {
        Name = Std.Trimsuffix.Invoke(new()
        {
            Input = serviceAccount.Email,
            Suffix = ".gserviceaccount.com",
        }).Apply(invoke => invoke.Result),
        Instance = main.Name,
        Type = "CLOUD_IAM_SERVICE_ACCOUNT",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.random.Id;
import com.pulumi.random.IdArgs;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
import com.pulumi.gcp.sql.User;
import com.pulumi.gcp.sql.UserArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.TrimsuffixArgs;
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 dbNameSuffix = new Id("dbNameSuffix", IdArgs.builder()
            .byteLength(4)
            .build());

        var main = new DatabaseInstance("main", DatabaseInstanceArgs.builder()
            .name(String.format("main-instance-%s", dbNameSuffix.hex()))
            .databaseVersion("POSTGRES_15")
            .settings(DatabaseInstanceSettingsArgs.builder()
                .tier("db-f1-micro")
                .databaseFlags(DatabaseInstanceSettingsDatabaseFlagArgs.builder()
                    .name("cloudsql.iam_authentication")
                    .value("on")
                    .build())
                .build())
            .build());

        var iamUser = new User("iamUser", UserArgs.builder()
            .name("me@example.com")
            .instance(main.name())
            .type("CLOUD_IAM_USER")
            .build());

        var iamServiceAccountUser = new User("iamServiceAccountUser", UserArgs.builder()
            .name(StdFunctions.trimsuffix(TrimsuffixArgs.builder()
                .input(serviceAccount.email())
                .suffix(".gserviceaccount.com")
                .build()).result())
            .instance(main.name())
            .type("CLOUD_IAM_SERVICE_ACCOUNT")
            .build());

    }
}
resources:
  dbNameSuffix:
    type: random:Id
    name: db_name_suffix
    properties:
      byteLength: 4
  main:
    type: gcp:sql:DatabaseInstance
    properties:
      name: main-instance-${dbNameSuffix.hex}
      databaseVersion: POSTGRES_15
      settings:
        tier: db-f1-micro
        databaseFlags:
          - name: cloudsql.iam_authentication
            value: on
  iamUser:
    type: gcp:sql:User
    name: iam_user
    properties:
      name: me@example.com
      instance: ${main.name}
      type: CLOUD_IAM_USER
  iamServiceAccountUser:
    type: gcp:sql:User
    name: iam_service_account_user
    properties:
      name:
        fn::invoke:
          function: std:trimsuffix
          arguments:
            input: ${serviceAccount.email}
            suffix: .gserviceaccount.com
          return: result
      instance: ${main.name}
      type: CLOUD_IAM_SERVICE_ACCOUNT

When type is set to CLOUD_IAM_USER or CLOUD_IAM_SERVICE_ACCOUNT, users authenticate with their Google Cloud credentials instead of passwords. The database instance must have the cloudsql.iam_authentication flag enabled. For service accounts, the name must match the account identifier without the .gserviceaccount.com suffix.

Authenticate IAM groups for team access

IAM group authentication allows entire Google Groups to access databases, simplifying access management for teams.

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

const dbNameSuffix = new random.index.Id("db_name_suffix", {byteLength: 4});
const main = new gcp.sql.DatabaseInstance("main", {
    name: `main-instance-${dbNameSuffix.hex}`,
    databaseVersion: "MYSQL_8_0",
    settings: {
        tier: "db-f1-micro",
        databaseFlags: [{
            name: "cloudsql_iam_authentication",
            value: "on",
        }],
    },
});
const iamGroupUser = new gcp.sql.User("iam_group_user", {
    name: "iam_group@example.com",
    instance: main.name,
    type: "CLOUD_IAM_GROUP",
});
import pulumi
import pulumi_gcp as gcp
import pulumi_random as random

db_name_suffix = random.index.Id("db_name_suffix", byte_length=4)
main = gcp.sql.DatabaseInstance("main",
    name=f"main-instance-{db_name_suffix['hex']}",
    database_version="MYSQL_8_0",
    settings={
        "tier": "db-f1-micro",
        "database_flags": [{
            "name": "cloudsql_iam_authentication",
            "value": "on",
        }],
    })
iam_group_user = gcp.sql.User("iam_group_user",
    name="iam_group@example.com",
    instance=main.name,
    type="CLOUD_IAM_GROUP")
package main

import (
	"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 {
		dbNameSuffix, err := random.NewId(ctx, "db_name_suffix", &random.IdArgs{
			ByteLength: 4,
		})
		if err != nil {
			return err
		}
		main, err := sql.NewDatabaseInstance(ctx, "main", &sql.DatabaseInstanceArgs{
			Name:            pulumi.Sprintf("main-instance-%v", dbNameSuffix.Hex),
			DatabaseVersion: pulumi.String("MYSQL_8_0"),
			Settings: &sql.DatabaseInstanceSettingsArgs{
				Tier: pulumi.String("db-f1-micro"),
				DatabaseFlags: sql.DatabaseInstanceSettingsDatabaseFlagArray{
					&sql.DatabaseInstanceSettingsDatabaseFlagArgs{
						Name:  pulumi.String("cloudsql_iam_authentication"),
						Value: pulumi.String("on"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		_, err = sql.NewUser(ctx, "iam_group_user", &sql.UserArgs{
			Name:     pulumi.String("iam_group@example.com"),
			Instance: main.Name,
			Type:     pulumi.String("CLOUD_IAM_GROUP"),
		})
		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 dbNameSuffix = new Random.Index.Id("db_name_suffix", new()
    {
        ByteLength = 4,
    });

    var main = new Gcp.Sql.DatabaseInstance("main", new()
    {
        Name = $"main-instance-{dbNameSuffix.Hex}",
        DatabaseVersion = "MYSQL_8_0",
        Settings = new Gcp.Sql.Inputs.DatabaseInstanceSettingsArgs
        {
            Tier = "db-f1-micro",
            DatabaseFlags = new[]
            {
                new Gcp.Sql.Inputs.DatabaseInstanceSettingsDatabaseFlagArgs
                {
                    Name = "cloudsql_iam_authentication",
                    Value = "on",
                },
            },
        },
    });

    var iamGroupUser = new Gcp.Sql.User("iam_group_user", new()
    {
        Name = "iam_group@example.com",
        Instance = main.Name,
        Type = "CLOUD_IAM_GROUP",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.random.Id;
import com.pulumi.random.IdArgs;
import com.pulumi.gcp.sql.DatabaseInstance;
import com.pulumi.gcp.sql.DatabaseInstanceArgs;
import com.pulumi.gcp.sql.inputs.DatabaseInstanceSettingsArgs;
import com.pulumi.gcp.sql.User;
import com.pulumi.gcp.sql.UserArgs;
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 dbNameSuffix = new Id("dbNameSuffix", IdArgs.builder()
            .byteLength(4)
            .build());

        var main = new DatabaseInstance("main", DatabaseInstanceArgs.builder()
            .name(String.format("main-instance-%s", dbNameSuffix.hex()))
            .databaseVersion("MYSQL_8_0")
            .settings(DatabaseInstanceSettingsArgs.builder()
                .tier("db-f1-micro")
                .databaseFlags(DatabaseInstanceSettingsDatabaseFlagArgs.builder()
                    .name("cloudsql_iam_authentication")
                    .value("on")
                    .build())
                .build())
            .build());

        var iamGroupUser = new User("iamGroupUser", UserArgs.builder()
            .name("iam_group@example.com")
            .instance(main.name())
            .type("CLOUD_IAM_GROUP")
            .build());

    }
}
resources:
  dbNameSuffix:
    type: random:Id
    name: db_name_suffix
    properties:
      byteLength: 4
  main:
    type: gcp:sql:DatabaseInstance
    properties:
      name: main-instance-${dbNameSuffix.hex}
      databaseVersion: MYSQL_8_0
      settings:
        tier: db-f1-micro
        databaseFlags:
          - name: cloudsql_iam_authentication
            value: on
  iamGroupUser:
    type: gcp:sql:User
    name: iam_group_user
    properties:
      name: iam_group@example.com
      instance: ${main.name}
      type: CLOUD_IAM_GROUP

Setting type to CLOUD_IAM_GROUP grants database access to all members of a Google Group. The database instance must have the cloudsql_iam_authentication flag enabled. This approach centralizes access control in Google Groups rather than managing individual database users.

Beyond these examples

These snippets focus on specific user-level features: password and IAM-based authentication, database role assignment, and user and group identity types. They’re intentionally minimal rather than full access management solutions.

The examples may reference pre-existing infrastructure such as Cloud SQL database instances, and IAM service accounts and Google Groups for IAM examples. They focus on configuring the user rather than provisioning the surrounding infrastructure.

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

  • Password policies (passwordPolicy)
  • Deletion policies for role-granted users (deletionPolicy)
  • Write-only password handling (passwordWo)
  • Host restrictions for MySQL (host property nuances)

These omissions are intentional: the goal is to illustrate how each user authentication method is wired, not provide drop-in access management modules. See the Cloud SQL User resource reference for all available configuration options.

Let's create GCP Cloud SQL Users

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Authentication & IAM
How do I use IAM authentication instead of passwords?
Set type to CLOUD_IAM_USER or CLOUD_IAM_SERVICE_ACCOUNT, enable the cloudsql.iam_authentication database flag on your instance, and omit the password field entirely.
Should I set a password for IAM-authenticated users?
No. Don’t set password or passwordWo for CLOUD_IAM_USER or CLOUD_IAM_SERVICE_ACCOUNT user types, as these authenticate via IAM credentials instead.
What's the difference between password and passwordWo?
Both set the user password, but passwordWo is write-only and won’t appear in state or read operations. Use passwordWo when you want to avoid storing passwords in state.
How do I use IAM group authentication?
Set type to CLOUD_IAM_GROUP, enable the appropriate IAM authentication flag (cloudsql_iam_authentication for MySQL or cloudsql.iam_authentication for Postgres), and use the group email as the name.
Why do I need to trim the suffix from service account emails?
When using CLOUD_IAM_SERVICE_ACCOUNT type, remove the .gserviceaccount.com suffix from the service account email using a function like trimsuffix.
Database-Specific Behavior
Can I set a host restriction for my Postgres user?
No. The host field is only supported for BUILT_IN users in MySQL instances. Don’t set it for PostgreSQL or SQL Server.
How do I assign database roles to a user?
Use the databaseRoles property with role names like cloudsqlsuperuser (MySQL 8+ and PostgreSQL only). Custom roles must be created in the database first using the CREATE ROLE statement.
User Management & Lifecycle
Why can't I delete my Postgres user?
Postgres users granted SQL roles cannot be deleted via the Cloud SQL API. Set deletionPolicy to ABANDON to allow Pulumi to abandon the resource instead of attempting deletion.
Why isn't my password showing up after import?
Passwords are not retrieved from the API during import for security reasons. You’ll need to set the password in your Pulumi code after importing.
What properties can't be changed after creation?
The host, instance, name, project, and type properties are immutable and require resource replacement if changed.
Why aren't my databaseRoles showing up in state?
The databaseRoles property is write-only and won’t be read from the API or appear in state after creation.

Using a different cloud?

Explore database guides for other cloud providers: