| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Provisions a google_sql_database_instance (MySQL, PostgreSQL, or SQL Server) together with its google_sql_database and google_sql_user child records, targeting hashicorp/google ~> 7.0.
💡 Why it matters: Cloud SQL instances are long-lived, stateful, and expensive to get wrong — a name-reuse cooldown of up to one week, two independent deletion guards, and an engine/edition interaction that fails only at apply time (not plan) are all real traps this module either closes at plan time or documents loudly rather than leaving the caller to discover them by reading an API error.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!
This module has no confirmed downstream consumer module in the current catalog — it is consumed directly by application-layer compute (Cloud Run, GKE, Cloud SQL Proxy sidecars) that sit outside this Terraform library's scope. Two sibling modules feed into it optionally, and one real cross-module gap sits directly upstream of the private-IP path:
flowchart LR
VPC["terraform-google-vpc-network\n(VPC network)"]:::sibling
KMS["terraform-google-kms-keyring\n(CMEK crypto key)"]:::sibling
SNC(("google_service_networking_connection\nNOT in this catalog — caller-owned")):::gap
SQL["terraform-google-cloud-sql-instance"]:::this
NONE["No confirmed downstream\nconsumer module yet"]:::sibling
VPC -- "self_link (optional, private IP)" --> SQL
KMS -- "crypto key id (optional CMEK)" --> SQL
SNC -. "required prerequisite if private IP is used — out of scope, caller must create".-> SQL
SQL -- "connection_name / self_link / id" --> NONE
classDef this fill:#4285F4,color:#ffffff,stroke:#174EA6,stroke-width:2px;
classDef sibling fill:#e8eaed,color:#202124,stroke:#9aa0a6,stroke-width:1px;
classDef gap fill:#ffffff,color:#5f6368,stroke:#d93025,stroke-width:2px,stroke-dasharray: 5 5;
terraform-google-vpc-network's self_link output feeds settings.ip_configuration.private_network only if the caller opts out of the public-IP default. terraform-google-kms-keyring's crypto_key_ids output feeds encryption_key_name for CMEK. The google_service_networking_connection node is dashed because it is a real, required prerequisite for private IP that this library does not own or create — see SCOPE.md and the ⚠️ callouts in the Example Library below.
Three resource types: one keystone, two independent for_each child collections.
flowchart TB
INSTANCE["google_sql_database_instance.this\n(keystone)"]:::keystone
DB["google_sql_database.databases\n(for_each over var.databases)"]:::this
USR["google_sql_user.users\n(for_each over var.users)"]:::this
INSTANCE -- "instance = google_sql_database_instance.this.name" --> DB
INSTANCE -- "instance = google_sql_database_instance.this.name" --> USR
classDef keystone fill:#174EA6,color:#ffffff,stroke:#174EA6,stroke-width:2px;
classDef this fill:#4285F4,color:#ffffff,stroke:#174EA6,stroke-width:2px;
| Resource | Cardinality | Notes |
|---|---|---|
| google_sql_database_instance.this | 1 | Keystone; MySQL, PostgreSQL, or SQL Server |
| google_sql_database.databases | 0..n (for_each over var.databases) | Independent lifecycle, never inline |
| google_sql_user.users | 0..n (for_each over var.users) | Write-only password only, never plaintext |
| Requirement | Value |
|---|---|
| Terraform | >= 1.12.0 |
| hashicorp/google | ~> 7.0 (resolved 7.39.0 at authoring time) |
| Provider block | None — the caller's root module configures google (ADC / WIF / service-account key) |
Schema notes that bite (all confirmed against the live, resolved 7.39.0 schema):
terraform-google-cloud-sql-instance/
├── providers.tf # required_providers + required_version — no provider {} block
├── variables.tf # instance/settings/databases/users object schemas, secure defaults
├── main.tf # google_sql_database_instance.this + 2 for_each child resources
├── outputs.tf # id, self_link, connection_name, name, region, IPs, child name maps
├── README.md # this file
├── SCOPE.md # cross-module contract
└── examples/
└── basic/ # smallest real call, matching Quick Start below
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "billing-primary"
database_version = "POSTGRES_15"
settings = {
tier = "db-custom-2-7680"
}
databases = {
"billing" = {}
}
users = {
"app_svc" = {
password_wo = var.app_svc_password
password_wo_version = 1
}
}
}The caller's root module configures the google provider (ADC, Workload Identity Federation, or a service-account key) — this module never declares project/region/zone/credentials.
Consumes
| Input | Type | Source module |
|---|---|---|
| settings.ip_configuration.private_network (optional) | string (.self_link) | terraform-google-vpc-network |
| encryption_key_name (optional) | string (full KMS crypto key resource path) | terraform-google-kms-keyring |
| (none required) — runs standalone with public-IP-disabled, no-CMEK defaults | — | — |
Emits
| Output | Description | Consumed by |
|---|---|---|
| id | Instance resource id | None confirmed yet in the catalog |
| self_link | Instance self_link (full API URL) | None confirmed yet |
| connection_name | {project}:{region}:{name} — the form Cloud SQL Proxy/Cloud Run/GKE sidecars actually want | App-layer compute outside this library's scope |
| name | Instance name | — |
| region | Effective region | — |
| public_ip_address / private_ip_address | Convenience computed IPs (null if not applicable) | Firewall/connection-string composition |
| database_names | Map of database key → name | — |
| user_names | Map of user key → name (never the password) | — |
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "app-mysql"
database_version = "MYSQL_8_0"
settings = {
tier = "db-f1-micro"
}
}2 · PostgreSQL with databases and an IAM-authenticated userℹ️ No databases/users supplied — a valid, empty-child-collection instance. Public IP stays disabled (ipv4_enabled = false default) with no authorized_networks, so nothing can connect until you add a private network or opt into public IP explicitly (Example 3).
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "reporting-postgres"
database_version = "POSTGRES_15"
settings = {
tier = "db-custom-4-15360"
}
databases = {
"reporting" = { charset = "UTF8", collation = "en_US.UTF8" }
}
users = {
"svc-reporting@my-project.iam" = {
type = "CLOUD_IAM_SERVICE_ACCOUNT"
}
}
}3 · Explicit public IP with authorized networks💡 CLOUD_IAM_SERVICE_ACCOUNT/CLOUD_IAM_USER types need no password_wo — leave it null (this module's users validation rejects setting it for those two types).
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "vendor-integration-mysql"
database_version = "MYSQL_8_0"
settings = {
tier = "db-f1-micro"
ip_configuration = {
ipv4_enabled = true
authorized_networks = {
"vendor-office" = { cidr_range = "203.0.113.0/24" }
"vendor-vpn" = { cidr_range = "198.51.100.4", expiration_time = "2027-01-01T00:00:00Z" }
}
}
}
}4 · SQL Server with a root write-only password⚠️ ipv4_enabled = true is an explicit opt-out of this module's secure default. Every authorized_networks entry is an open inbound path from that CIDR — keep the list as narrow as possible and set expiration_time for anything temporary.
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "legacy-app-sqlserver"
database_version = "SQLSERVER_2022_STANDARD"
root_password_wo = var.sqlserver_root_password
root_password_wo_version = 1
settings = {
tier = "db-custom-4-15360"
edition = "ENTERPRISE"
ip_configuration = {
ssl_mode = "ENCRYPTED_ONLY"
}
}
}5 · Custom database flags (Cloud SQL IAM database authentication)🔒 root_password_wo is required for SQL Server and, like every password in this module, is write-only — never persisted to Terraform state. Increment root_password_wo_version whenever the value changes.
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "iam-auth-postgres"
database_version = "POSTGRES_15"
settings = {
tier = "db-custom-2-7680"
database_flags = {
"cloudsql.iam_authentication" = "on"
}
}
users = {
"engineer@example.com" = { type = "CLOUD_IAM_USER" }
}
}6 · High-availability PostgreSQL (REGIONAL) with maintenance windowℹ️ database_flags is a map(string) (flag name → value) rather than a list — flag names are already unique identities, so a map gives stable for_each-style behavior without a list-index diff when a flag is added or removed.
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "core-ledger-postgres"
database_version = "POSTGRES_15"
settings = {
tier = "db-custom-8-30720"
availability_type = "REGIONAL"
maintenance_window = {
day = 7
hour = 3
update_track = "stable"
}
}
}7 · PostgreSQL 16+ with a shared-core tier (edition trap, avoided)💡 availability_type = "REGIONAL" requires settings.backup_configuration.enabled = true (this module's default) — for PostgreSQL, also ensure PITR stays enabled (also this module's default for non-MySQL engines).
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "budget-postgres16"
database_version = "POSTGRES_16"
settings = {
tier = "db-f1-micro"
edition = "ENTERPRISE" # required — see ⚠️ below
}
}8 · Private IP (with the required peering prerequisite)⚠️ PostgreSQL 16+ auto-defaults to edition = "ENTERPRISE_PLUS" when edition is omitted, and ENTERPRISE_PLUS only accepts db-perf-optimized-N-*/db-perf-optimized-C4A-* tiers. Omitting edition here with tier = "db-f1-micro" fails this module's plan-time validation — set edition = "ENTERPRISE" explicitly whenever you want a shared-core or custom tier on PostgreSQL 16 or later.
# In the SAME composition — NOT owned by terraform-google-cloud-sql-instance:
resource "google_compute_global_address" "private_ip_range" {
name = "cloud-sql-psa-range"
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = 16
network = module.vpc_network.id
}
resource "google_service_networking_connection" "private_vpc_connection" {
network = module.vpc_network.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.private_ip_range.name]
}
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "private-only-mysql"
database_version = "MYSQL_8_0"
settings = {
tier = "db-custom-2-7680"
ip_configuration = {
ipv4_enabled = false
private_network = module.vpc_network.self_link
enable_private_path_for_google_cloud_services = true
}
}
depends_on = [google_service_networking_connection.private_vpc_connection]
}9 · Multiple databases and users in one instance⚠️ google_service_networking_connection is out of scope for this module and is not in the current catalog. You must create it yourself in the consuming composition, exactly as shown. The google_sql_database_instance resource does not auto-interpolate a dependency on this peering — the explicit depends_on shown above is required, per the resource's own documented caveat, or the instance creation can race the peering and fail.
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "shared-mysql"
database_version = "MYSQL_8_0"
settings = {
tier = "db-custom-4-15360"
}
databases = {
"orders" = {}
"invoices" = {}
"audit" = {}
}
users = {
"orders_svc" = { host = "10.0.%.%", password_wo = var.orders_pw, password_wo_version = 1 }
"invoices_svc" = { host = "10.0.%.%", password_wo = var.invoices_pw, password_wo_version = 1 }
"readonly_bi" = { host = "%", password_wo = var.bi_pw, password_wo_version = 1 }
}
}10 · Rotating a user's write-only passwordℹ️ host is only valid for BUILT_IN users on MySQL — each map key is independently force-new, so adding or removing one database/user entry never touches the others.
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "app-mysql"
database_version = "MYSQL_8_0"
settings = { tier = "db-f1-micro" }
users = {
"app_svc" = {
password_wo = var.app_svc_password_v2 # new secret value
password_wo_version = 2 # incremented from 1 — this triggers the update
}
}
}11 · Password validation policy for BUILT_IN users🔒 Write-only arguments carry no value in state, so Terraform only detects a password rotation via the incremented password_wo_version counter — changing password_wo's value alone, without bumping the version, produces no diff.
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "hardened-postgres"
database_version = "POSTGRES_15"
settings = {
tier = "db-custom-2-7680"
password_validation_policy = {
enable_password_policy = true
min_length = 14
disallow_username_substring = true
reuse_interval = 5
complexity = "COMPLEXITY_DEFAULT"
}
}
users = {
"dba_admin" = {
password_wo = var.dba_admin_password
password_wo_version = 1
password_policy = {
enable_failed_attempts_check = true
allowed_failed_attempts = 5
}
}
}
}12 · Decommissioning: the two-step deletion-protection applyℹ️ password_validation_policy (instance-level) and password_policy (per-user) are both only supported for MySQL and PostgreSQL — not SQL Server.
# Step 1 — flip both guards to false and apply (writes the change to state,
# does NOT delete anything yet):
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "retiring-instance"
database_version = "MYSQL_8_0"
deletion_protection = false # was true (default)
settings = {
tier = "db-f1-micro"
deletion_protection_enabled = false # was true (default)
}
}
# Step 2 — after that apply succeeds, remove the module block (or run
# terraform destroy) to actually delete the instance.13 · Abandoning a user Terraform cannot delete (Postgres SQL roles)⚠️ Skipping step 1 and going straight to terraform destroy fails: deletion_protection blocks the destroy inside Terraform, and even if that were bypassed, settings.deletion_protection_enabled blocks it at the API level too. See Troubleshooting.
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "roles-postgres"
database_version = "POSTGRES_15"
settings = { tier = "db-custom-2-7680" }
users = {
"role_holder" = {
password_wo = var.role_holder_password
password_wo_version = 1
deletion_policy = "ABANDON" # this user has been granted SQL roles; the API refuses DELETE
}
}
}14 · CMEK-encrypted instanceℹ️ Confirmed schema note on google_sql_user.deletion_policy: "ABANDON" is "useful for Postgres, where users cannot be deleted from the API if they have been granted SQL roles." This removes the record from Terraform state without calling the delete API — the database role itself must still be revoked out-of-band if it needs to go away.
module "kms" {
source = "git::https://github.com/microsoftexpert/terraform-google-kms-keyring.git?ref=v1.0.0"
key_ring_name = "cloud-sql-cmek"
location = "us-east1"
crypto_keys = {
"cloud-sql-key" = { purpose = "ENCRYPT_DECRYPT" }
}
}
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "cmek-encrypted-mysql"
database_version = "MYSQL_8_0"
region = "us-east1" # must match the KMS key's location
encryption_key_name = module.kms.crypto_key_ids["cloud-sql-key"]
settings = {
tier = "db-custom-2-7680"
}
}15 · 🏗️ End-to-end composition — VPC, CMEK, private IP, databases, and users🔒 The CMEK key must be in the same region as the instance. Manual, non-Terraform steps are still required (see ☁️ GCP Prerequisites) — this module accepts encryption_key_name but cannot grant the Cloud SQL service account access to the key on your behalf.
module "vpc_network" {
source = "git::https://github.com/microsoftexpert/terraform-google-vpc-network.git?ref=v1.0.0"
network_name = "data-tier-vpc"
subnetworks = {
"data-tier-use1" = { ip_cidr_range = "10.20.0.0/24", region = "us-east1" }
}
}
module "kms" {
source = "git::https://github.com/microsoftexpert/terraform-google-kms-keyring.git?ref=v1.0.0"
key_ring_name = "data-tier-cmek"
location = "us-east1"
crypto_keys = {
"cloud-sql-key" = { purpose = "ENCRYPT_DECRYPT" }
}
}
# google_service_networking_connection is a real, required prerequisite this
# library does not own — see ⚠️ Example 8 and SCOPE.md.
resource "google_compute_global_address" "private_ip_range" {
name = "data-tier-psa-range"
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = 16
network = module.vpc_network.id
}
resource "google_service_networking_connection" "private_vpc_connection" {
network = module.vpc_network.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.private_ip_range.name]
}
module "cloud_sql" {
source = "git::https://github.com/microsoftexpert/terraform-google-cloud-sql-instance.git?ref=v1.0.0"
instance_name = "data-tier-postgres"
database_version = "POSTGRES_16"
region = "us-east1"
encryption_key_name = module.kms.crypto_key_ids["cloud-sql-key"]
settings = {
tier = "db-custom-4-15360"
edition = "ENTERPRISE" # required for a non-perf-optimized tier on PG16+, see Example 7
availability_type = "REGIONAL"
ip_configuration = {
ipv4_enabled = false
private_network = module.vpc_network.self_link
}
backup_configuration = {
enabled = true # point_in_time_recovery_enabled defaults true for PostgreSQL
}
}
databases = {
"app_primary" = { charset = "UTF8", collation = "en_US.UTF8" }
}
users = {
"app_svc" = {
password_wo = var.app_svc_password
password_wo_version = 1
}
"svc-account@my-project.iam" = {
type = "CLOUD_IAM_SERVICE_ACCOUNT"
}
}
labels = {
environment = "prod"
data_tier = "postgres"
}
depends_on = [google_service_networking_connection.private_vpc_connection]
}
output "cloud_sql_connection_name" {
value = module.cloud_sql.connection_name
}💡 This wires terraform-google-vpc-network's self_link output into private_network, terraform-google-kms-keyring's crypto_key_ids output into encryption_key_name, satisfies the google_service_networking_connection prerequisite explicitly (with the required depends_on), and avoids the PostgreSQL 16+ edition trap from Example 7 — the full shape a real production composition needs, not just the module call in isolation.
Top-level: instance_name (required) · database_version (required, engine-family validated) · region (optional) · deletion_protection (default true) · deletion_policy (default "DELETE") · encryption_key_name (optional CMEK) · final_backup_description (optional) · root_password_wo/root_password_wo_version (SQL Server only) · labels (default {}) · timeouts (instance-scoped only)
settings (required — only tier is mandatory): engine/machine configuration, ip_configuration (secure default ipv4_enabled = false), backup_configuration (secure default enabled = true, engine-gated PITR/binary-log), final_backup_config, database_flags (map(string)), maintenance_window, insights_config (secure-ish default query_insights_enabled = true), password_validation_policy, advanced_machine_features, location_preference, data_cache_config.
databases (map(object(...)), default {}): charset, collation, deletion_policy, timeouts.
users (map(object(...)), default {}): type (default "BUILT_IN"), host (MySQL BUILT_IN only, force-new), password_wo/password_wo_version (write-only, never plaintext), database_roles, deletion_policy, password_policy, timeouts.
Full object schemasSee variables.tf in full — every field is documented inline with its default, validation, and (where relevant) force-new/engine-gating behavior. The file-level comment block at the top of variables.tf documents six cross-cutting design decisions (the labels → settings.user_labels mapping, the three deletion guards, the private_network self_link finding, the PostgreSQL 16+/edition validation, the full excluded-by-design block list, and the asymmetric timeouts) before any individual variable.
| Output | Description |
|---|---|
| id | Instance Terraform-internal resource id |
| self_link | Instance self_link (full API URL) |
| connection_name | The form most consumers actually want — Cloud SQL Proxy/Cloud Run/GKE sidecar connection string |
| name | Instance name |
| region | Effective region |
| public_ip_address | First public IPv4, null if ipv4_enabled = false |
| private_ip_address | First private IPv4, null unless private IP is configured and the peering prerequisite exists |
| maintenance_version | Currently-applied maintenance version (computed) |
| database_names | Map of database key → name |
| user_names | Map of user key → name — never the password |
No output ever surfaces a password, write-only or otherwise — there is nothing to surface, since this module never reads one back.
| Concern | Secure default | Opt-out (explicit) |
|---|---|---|
| Public IP | settings.ip_configuration.ipv4_enabled = false | Caller sets true and supplies authorized_networks |
| Deletion (Terraform) | deletion_protection = true | Caller sets false |
| Deletion (API, all surfaces) | settings.deletion_protection_enabled = true | Caller sets false — both must flip for a destroy to succeed |
| Backups | settings.backup_configuration.enabled = true | Caller sets false |
| Point-in-time recovery (PostgreSQL/SQL Server) | point_in_time_recovery_enabled = true (engine-gated) | Caller sets false in backup_configuration |
| Binary logging (MySQL, PITR-equivalent) | binary_log_enabled = true (engine-gated) | Caller sets false in backup_configuration |
| Encryption at rest (CMEK) | Accepted via encryption_key_name, never defaulted to a specific key | Caller supplies a key from terraform-google-kms-keyring |
| TLS enforcement | settings.ip_configuration.ssl_mode = "ENCRYPTED_ONLY" (module extension — not a house-table row verbatim) | Caller sets "ALLOW_UNENCRYPTED_AND_ENCRYPTED" or "TRUSTED_CLIENT_CERTIFICATE_REQUIRED" |
| ExecuteSql (Data API) access | settings.data_api_access = "DISALLOW_DATA_API" (module extension) | Caller sets "ALLOW_DATA_API" |
| Query Insights (observability) | settings.insights_config.query_insights_enabled = true (module extension of this module suite's audit-logging posture) | Caller sets false |
| Query Insights client-address capture | record_client_address = false (left off — data-handling caution) | Caller sets true |
| User passwords | Write-only password_wo/password_wo_version only — no plaintext password argument exists in this module | N/A — by design |
cd terraform-google-cloud-sql-instance
terraform init -backend=false
terraform validate
terraform fmt -checkPin ?ref=v1.0.0 in every source = line — never a branch. This library is plan-only; a human applies from CI with real Workload Identity Federation credentials against a specific project.
init -backend=false / validate / fmt -check confirm internal type/reference consistency and canonical formatting only. Given this resource's schema is enforced heavily server-side (quota, region/edition availability, the PostgreSQL 16+/edition interaction this module catches at plan time notwithstanding, org policy, and the private-IP peering prerequisite this module cannot see), a clean validate is not a guarantee that apply will succeed against a real project. The examples/basic/ directory exists so a consuming GitHub Actions workflow can run a real terraform plan with valid WIF credentials as part of its own review gate.
$ terraform output
connection_name = "my-project:us-east1:data-tier-postgres"
database_names = {
"app_primary" = "app_primary"
}
id = "projects/my-project/instances/data-tier-postgres"
name = "data-tier-postgres"
private_ip_address = "10.20.0.3"
public_ip_address = null
region = "us-east1"
self_link = "https://sqladmin.googleapis.com/sql/v1beta4/projects/my-project/instances/data-tier-postgres"
user_names = {
"app_svc" = "app_svc"
"svc-account@my-project.iam" = "svc-account@my-project.iam"
}
| Symptom | Cause | Fix |
|---|---|---|
| apply fails re-creating an instance with a name that was just destroyed | Cloud SQL enforces a name-reuse cooldown of up to one week after deletion — confirmed schema text, not a vague "some delay" | Wait out the cooldown, or choose a different instance_name |
| terraform destroy fails even after setting deletion_protection = false | settings.deletion_protection_enabled (API-level) is still true — it is a separate guard from deletion_protection | Set both deletion_protection = false AND settings.deletion_protection_enabled = false, apply that change first, then destroy |
| apply fails with a private-IP-related API error even though plan showed no problem | settings.ip_configuration.private_network is set but the required google_service_networking_connection peering does not exist (or the instance was created before the peering finished, due to a missing depends_on) | Create the peering in the consuming composition (Example 8) and add the explicit depends_on — terraform plan cannot detect this gap |
| apply fails with an "Invalid Tier... for (ENTERPRISE_PLUS) Edition" error | database_version is PostgreSQL 16+, settings.tier is a shared-core/custom tier, and settings.edition was left unset — PG16+ auto-defaults to ENTERPRISE_PLUS | This module's own validation on settings should catch this at plan time (Example 7) — if you see it at apply regardless, confirm you are on a provider version where this auto-default behavior still applies |
| apply rejects binary_log_enabled/point_in_time_recovery_enabled | Sent the wrong one for the engine family — binary_log_enabled is MySQL-only, point_in_time_recovery_enabled is PostgreSQL/SQL-Server-only | Let this module's engine-gating handle it automatically; only override the field matching your actual database_version |
| A google_sql_user won't delete | The user has been granted PostgreSQL SQL roles, which the API refuses to delete out from under | Set that user's deletion_policy = "ABANDON" (Example 13) and revoke the role separately if needed |
| Back | FazBrowse Home | New Git URL |