Create GCP Cloud SQL Users

The gcp:sql/user:User resource, part of the Pulumi GCP provider, creates database users on Cloud SQL instances with password or IAM-based authentication. This guide focuses on three capabilities: password-based authentication, Cloud IAM user and service account authentication, and IAM group-based access.

Database users belong to Cloud SQL instances and may reference IAM principals that must exist separately. The examples are intentionally small. Combine them with your own Cloud SQL instances and IAM configuration.

Create a user with password authentication

Most deployments start with built-in database users that authenticate with passwords, providing immediate access for applications and administrators.

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 (
	"fmt"

	"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. The instance property references the Cloud SQL instance. For MySQL users, the host property restricts which hosts can connect (use an IP address or hostname). The password property sets the authentication credential. Without specifying type, the user defaults to BUILT_IN authentication.

Authenticate users with Cloud IAM

Teams managing access through Google Cloud IAM can create database users that authenticate using IAM credentials, eliminating password management.

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 (
	"fmt"

	"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

The type property determines authentication method. CLOUD_IAM_USER grants access to individual IAM users; CLOUD_IAM_SERVICE_ACCOUNT grants access to service accounts. The instance must have the cloudsql.iam_authentication database flag enabled (shown in the databaseFlags array). IAM-authenticated users don’t use the password property. For service accounts, the name must match the service account email without the .gserviceaccount.com suffix.

Grant access to IAM groups

Organizations with many users can grant database access to entire IAM groups, allowing group membership changes to automatically affect database permissions.

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 (
	"fmt"

	"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

The CLOUD_IAM_GROUP type grants access to all members of an IAM group. The name property must match the group email. Like individual IAM users, group-based users require the cloudsql_iam_authentication database flag (MySQL) or cloudsql.iam_authentication (PostgreSQL). Group members inherit database access without individual user creation.

Beyond these examples

These snippets focus on specific user-level features: password and IAM authentication, and user types (built-in, IAM user, service account, group). They’re intentionally minimal rather than full database access configurations.

The examples reference pre-existing infrastructure such as Cloud SQL instances with appropriate database flags, and IAM users, service accounts, or groups. They focus on creating database users rather than provisioning the surrounding infrastructure.

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

  • Password policies (passwordPolicy)
  • Deletion policies for Postgres users with SQL roles (deletionPolicy)
  • Host restrictions for MySQL users
  • Write-only password handling (passwordWo)

These omissions are intentional: the goal is to illustrate how each user authentication method is wired, not provide drop-in access control 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 & Passwords
When is the password field required?
For Postgres instances, password is required unless type is set to CLOUD_IAM_USER or CLOUD_IAM_SERVICE_ACCOUNT. Don’t set password for any IAM user types (CLOUD_IAM_USER, CLOUD_IAM_SERVICE_ACCOUNT, CLOUD_IAM_GROUP) on any Cloud SQL instance.
What's the difference between password and passwordWo?
passwordWo is write-only and won’t appear in state after creation, while password is readable. Use passwordWoVersion to track updates to passwordWo.
How do I enable IAM authentication for Cloud SQL users?
Enable the database flag cloudsql.iam_authentication (Postgres) or cloudsql_iam_authentication (MySQL) with value on, then create users with type set to CLOUD_IAM_USER, CLOUD_IAM_SERVICE_ACCOUNT, or CLOUD_IAM_GROUP.
How do I create different IAM user types?
For IAM users, set type to CLOUD_IAM_USER with the user’s email as name. For service accounts, use CLOUD_IAM_SERVICE_ACCOUNT with the account name without .gserviceaccount.com suffix. For groups, use CLOUD_IAM_GROUP with the group email.
Database-Specific Configuration
When should I use the host field?
The host field is only supported for BUILT_IN users in MySQL instances. Don’t set this field for PostgreSQL or SQL Server instances. It can be an IP address and is immutable.
How do I import users into Pulumi?
MySQL users require the format {{project_id}}/{{instance}}/{{host}}/{{name}}. PostgreSQL users use {{project_id}}/{{instance}}/{{name}} without the host field.
Deletion & Lifecycle
Why can't I delete my Postgres user?
Postgres users granted SQL roles cannot be deleted through the API. Set deletionPolicy to ABANDON to allow the resource to be abandoned rather than deleted.
What properties are immutable after creation?
The name, instance, host, project, and type fields are all immutable and require resource replacement if changed.
User Types & Authentication Methods
What user types are available?
Available types include BUILT_IN (default), CLOUD_IAM_USER, CLOUD_IAM_SERVICE_ACCOUNT, CLOUD_IAM_GROUP, CLOUD_IAM_GROUP_USER, and CLOUD_IAM_GROUP_SERVICE_ACCOUNT. The type determines the authentication method during login.
What's the default user type if I don't specify one?
The default is the database’s built-in user type (BUILT_IN), which uses traditional username/password authentication.

Using a different cloud?

Explore database guides for other cloud providers: