Back to blog
Best PracticesCloud SecurityDatabasesGCPNetworking

Cloud SQL Accessible From 0.0.0.0/0: Why It's Dangerous and How to Fix It

A GCP Cloud SQL instance open to 0.0.0.0/0 exposes your database to the internet. Learn the risks and step-by-step fixes with gcloud, Terraform, and policy.

TL;DR

This check flags any Cloud SQL instance with an authorized network of 0.0.0.0/0, meaning the entire internet can reach your database port. Lock it down by removing the open authorized network and using Private IP or the Cloud SQL Auth Proxy instead.

A managed database is convenient until it is reachable by everyone on the planet. The Cloud SQL Accessible From 0.0.0.0/0 check catches one of the most common and most dangerous GCP database misconfigurations: a Cloud SQL instance configured to accept connections from any IP address. This post explains what the check looks for, why an open authorized network is a serious risk, and exactly how to fix and prevent it.


What this check detects

Cloud SQL instances with a public IP can define authorized networks, which are CIDR ranges allowed to connect to the database. When one of those ranges is 0.0.0.0/0, the instance accepts inbound connections from the entire IPv4 internet on its database port (3306 for MySQL, 5432 for PostgreSQL, 1433 for SQL Server).

The sql_publicaccess check inspects the ipConfiguration.authorizedNetworks field of every Cloud SQL instance in scope and fails any instance where a network entry has a value of 0.0.0.0/0.

Note: An authorized network only controls which IPs can open a TCP connection. Database authentication still applies on top of it. But network exposure removes your first and most effective layer of defense, leaving credentials and the database engine as the only barrier.


Why it matters

Exposing a database to the open internet turns a private datastore into a public attack surface. Here is what that actually means in practice.

Credential brute force and password spraying

Once the port is reachable, automated scanners find it within hours. Shodan and Censys index public Cloud SQL endpoints continuously, and bots probe known database ports nonstop. If your database uses a weak or default password, or a username like root with no IP restriction, brute force is trivial.

Exploitation of engine vulnerabilities

Database engines have a history of authentication bypass and remote code execution bugs. An internet-reachable instance means any unpatched CVE in your engine version becomes directly exploitable. With Private IP or no public exposure, an attacker would first need a foothold inside your network.

Data exfiltration and ransomware

Open MySQL and PostgreSQL instances are a favorite target for data theft and ransom schemes. Attackers dump tables, drop the data, and leave a ransom note in a table demanding payment to "restore" it. This has happened at scale to thousands of exposed databases.

Danger: A database open to 0.0.0.0/0 holding customer or PII data is a reportable breach risk under GDPR, CCPA, HIPAA, and PCI DSS. Even if no data is stolen, the exposure alone can trigger compliance findings and mandatory disclosure obligations.


How to fix it

The right fix depends on how your application connects. In nearly all cases the goal is the same: remove 0.0.0.0/0 and replace it with something tightly scoped or, better, no public IP at all.

Step 1: Find the offending instances

gcloud sql instances list --format="table(name, region, settings.ipConfiguration.authorizedNetworks)"

Inspect a specific instance to see its current authorized networks:

gcloud sql instances describe INSTANCE_NAME \
  --format="json(settings.ipConfiguration)"

Step 2: Remove the open authorized network

If you genuinely need a public IP, replace the open range with the specific IPs that should connect. The --authorized-networks flag overwrites the full list, so pass every range you want to keep.

Warning: This command replaces the entire authorized networks list and can immediately drop active connections from clients that are no longer in the allowlist. Confirm your application's egress IPs before applying, and run it during a maintenance window if connections are long-lived.

gcloud sql instances patch INSTANCE_NAME \
  --authorized-networks=203.0.113.10/32,198.51.100.0/24

To remove all authorized networks entirely:

gcloud sql instances patch INSTANCE_NAME \
  --clear-authorized-networks

Step 3: Prefer Private IP over public access

The strongest fix is to stop exposing the instance publicly at all. Enable Private IP so the database is only reachable over your VPC, then disable the public IP once your clients are migrated.

# Enable Private IP on an existing instance (requires a configured VPC and
# private services access connection)
gcloud sql instances patch INSTANCE_NAME \
  --network=projects/PROJECT_ID/global/networks/VPC_NAME \
  --no-assign-ip

Note: Private IP requires a Private Services Access connection between your VPC and Google's service producer network. If you have not set this up, create an allocated IP range and a VPC peering connection first, otherwise the patch will fail.

Step 4: Use the Cloud SQL Auth Proxy for application access

For applications and developers that need to connect without a public IP, the Cloud SQL Auth Proxy provides an encrypted, IAM-authenticated tunnel. It removes the need for authorized networks entirely.

# Run the proxy locally, connecting over a secure tunnel
./cloud-sql-proxy --private-ip PROJECT_ID:REGION:INSTANCE_NAME

Tip: In GKE, run the Auth Proxy as a sidecar container and have your app connect to 127.0.0.1. You get IAM-based auth and TLS without managing IP allowlists or static credentials.

Fixing it in Terraform

If your instances are managed with Terraform, fix the source and let the pipeline apply it so the change does not drift back:

resource "google_sql_database_instance" "main" {
  name             = "app-db"
  database_version = "POSTGRES_15"
  region           = "us-central1"

  settings {
    tier = "db-custom-2-7680"

    ip_configuration {
      ipv4_enabled    = false
      private_network = google_compute_network.vpc.id
      # No authorized_networks block. No 0.0.0.0/0.
      ssl_mode        = "ENCRYPTED_ONLY"
    }
  }
}

How to prevent it from happening again

Manual fixes do not stick. The open range tends to creep back in when someone debugs a connection issue and "temporarily" opens it up. Bake the rule into your pipeline and your org policies.

Enforce an Organization Policy

GCP ships a built-in constraint that blocks public IPs on Cloud SQL across your entire org or folder:

gcloud resource-manager org-policies enable-enforce \
  sql.restrictPublicIp \
  --organization=ORGANIZATION_ID

With this enforced, any attempt to create or patch a Cloud SQL instance with a public IP is rejected at the API level, regardless of who runs it.

Gate Terraform with policy-as-code

Add an OPA or Conftest policy that fails CI when a plan introduces an open authorized network:

package cloudsql

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "google_sql_database_instance"
  net := resource.change.after.settings[_].ip_configuration[_].authorized_networks[_]
  net.value == "0.0.0.0/0"
  msg := sprintf("Cloud SQL instance '%s' allows public access from 0.0.0.0/0", [resource.address])
}

Tip: Run this check in your pull request pipeline, not just on merge. Catching the misconfiguration before it reaches an apply step is the difference between a code review comment and an incident.

Continuous monitoring

Org policies and CI gates cover changes you control. Continuous scanning with Lensix catches drift, instances created out of band, and resources in projects that predate your policy rollout. Schedule the sql_publicaccess check to run regularly so an open instance gets flagged within minutes, not at the next audit.


Best practices

  • Default to Private IP. Public IP should be the exception with a documented reason, not the starting point.
  • Never use 0.0.0.0/0 as an authorized network. If you need broad access, fix the architecture with the Auth Proxy or a bastion, not an open allowlist.
  • Require SSL/TLS. Set ssl_mode = ENCRYPTED_ONLY so connections cannot fall back to plaintext even when reachable.
  • Use IAM database authentication where supported, so connections rely on short-lived tokens instead of static passwords.
  • Scope authorized networks to /32 host ranges when public access is unavoidable, and document each entry's owner and purpose.
  • Audit regularly. IP ranges go stale. Review authorized networks on a schedule and remove anything you cannot account for.

An open Cloud SQL instance is one of those misconfigurations that looks harmless on a quiet day and catastrophic the moment a scanner finds it. The fix is cheap, the prevention is automatable, and the downside of ignoring it is a breach. Close the range, move to Private IP, and let policy enforcement keep it that way.