Back to blog
Cloud SecurityDatabasesGCPMonitoring & LoggingOperations & Compliance

PostgreSQL Connection Logging Disabled on GCP Cloud SQL

Cloud SQL PostgreSQL instances without log_connections leave you blind during audits and incidents. Learn why it matters and how to enable connection logging.

TL;DR

This check flags Cloud SQL for PostgreSQL instances where the log_connections flag is off, which means you have no record of who connected and when. Turn it on by setting the log_connections database flag to on with a single gcloud command.

When something goes wrong with a database, the first question an incident responder asks is "who connected to it?" On a GCP Cloud SQL PostgreSQL instance with connection logging disabled, you cannot answer that question. There is no trail of successful authentications, no log of which client or service account opened a session, and no way to retroactively spot a connection that should never have happened.

The sql_pgconnections check looks at every Cloud SQL PostgreSQL instance in your project and reports any instance where the log_connections database flag is not set to on. It is a small flag with an outsized impact on your ability to investigate and audit.


What this check detects

PostgreSQL exposes a configuration parameter called log_connections. When enabled, the server writes a log line every time a client successfully connects, including the authentication method used and the user that authenticated. On Cloud SQL, this parameter is exposed as a database flag that you can toggle per instance.

The check passes when an instance has:

{
  "name": "log_connections",
  "value": "on"
}

It fails when the flag is absent, set to off, or otherwise not enabled. By default, Cloud SQL PostgreSQL does not enable this flag, so newly created instances will fail this check until you explicitly turn it on.

Note: log_connections logs successful connections. Its sibling flag, log_disconnections, records when sessions end and how long they lasted. They are separate flags, and a complete audit picture usually wants both enabled.


Why it matters

Connection logs are the foundation of database audit and incident response. Without them, you are flying blind in exactly the moments where visibility matters most.

You cannot investigate a breach

Suppose a service account credential leaks and an attacker uses it to connect to your production database. With connection logging on, you have timestamped records of every session opened with that identity, the source, and the auth method. You can scope the blast radius, identify the window of compromise, and feed that into your incident timeline. With logging off, the attacker's sessions look identical to legitimate traffic, which is to say, invisible.

You fail compliance audits

Frameworks like PCI DSS, SOC 2, HIPAA, and ISO 27001 expect you to log access to systems holding sensitive data. PCI DSS requirement 10 specifically calls for tracking all access to cardholder data, and an auditor will ask to see your database access logs. "We don't log connections" is not an answer that passes an audit.

Warning: Connection logs can grow quickly on busy instances with short-lived connections, especially without connection pooling. High log volume increases Cloud Logging ingestion costs and can add minor overhead. Pair this flag with a pooler like PgBouncer to keep churn down.

You miss the early signs of abuse

Connection logs feed detection. A sudden spike in connections from an unfamiliar IP, repeated connections outside business hours, or a service account connecting from a region it never uses are all signals you can alert on, but only if the connections are being logged in the first place.


How to fix it

Enabling connection logging is a one-flag change. You can do it from the console, the CLI, or your infrastructure-as-code tooling.

Option 1: gcloud CLI

Set the log_connections flag on the instance. This command preserves existing flags only if you list them all, so use a combined update if you already have flags set.

Warning: Changing certain database flags requires a restart of the Cloud SQL instance, which causes a brief connection interruption. log_connections can be applied without a restart on most PostgreSQL versions, but plan the change during a maintenance window if you are unsure.

gcloud sql instances patch my-pg-instance \
  --database-flags=log_connections=on,log_disconnections=on

Danger: gcloud sql instances patch --database-flags replaces the entire set of flags rather than merging. If your instance already has other flags configured, you must include them all in the same command or they will be silently removed. Check the current flags first.

Before patching, dump the existing flags so you do not lose any:

gcloud sql instances describe my-pg-instance \
  --format="value(settings.databaseFlags)"

Then include every existing flag plus the new ones in your patch command:

gcloud sql instances patch my-pg-instance \
  --database-flags=cloudsql.iam_authentication=on,log_connections=on,log_disconnections=on

Option 2: Google Cloud Console

  1. Open SQL in the Cloud console and select your PostgreSQL instance.
  2. Click Edit.
  3. Expand Flags.
  4. Click Add a database flag, choose log_connections, and set the value to on.
  5. Optionally add log_disconnections set to on as well.
  6. Click Save and confirm any restart prompt.

Option 3: Terraform

If you manage Cloud SQL with Terraform, add the flag to the instance settings so the configuration is enforced on every apply.

resource "google_sql_database_instance" "postgres" {
  name             = "my-pg-instance"
  database_version = "POSTGRES_15"
  region           = "us-central1"

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

    database_flags {
      name  = "log_connections"
      value = "on"
    }

    database_flags {
      name  = "log_disconnections"
      value = "on"
    }
  }
}

Tip: Because Terraform's database_flags is a managed set, you do not have the merge problem the CLI has. Declare every flag you want in the resource and Terraform reconciles the full set on apply, so nothing gets dropped accidentally.

Verify the change

Confirm the flag is applied and then check that connection lines are landing in Cloud Logging:

gcloud sql instances describe my-pg-instance \
  --format="value(settings.databaseFlags)"

gcloud logging read \
  'resource.type="cloudsql_database" AND textPayload:"connection authorized"' \
  --limit=10 \
  --format="value(textPayload)"

How to prevent it from happening again

Fixing one instance is easy. Making sure the next instance someone spins up does not regress is the real win. The goal is to make connection logging a default that is enforced rather than a setting someone has to remember.

Enforce with Organization Policy and a module

The most reliable approach is to wrap Cloud SQL provisioning in a shared Terraform module that bakes in the logging flags. Teams call the module, and they get a correctly configured instance whether they think about logging or not.

module "postgres" {
  source = "git::https://example.com/modules/cloudsql-postgres.git"

  name   = "orders-db"
  region = "us-central1"
  # log_connections and log_disconnections are set to "on"
  # inside the module and cannot be overridden to off
}

Gate it in CI/CD with policy-as-code

Add a policy check to your pipeline so a plan that disables or omits connection logging fails before it merges. With Conftest and Open Policy Agent against a Terraform plan, a rule looks like this:

package main

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "google_sql_database_instance"
  flags := resource.change.after.settings[_].database_flags
  not has_log_connections(flags)
  msg := sprintf("Cloud SQL instance '%s' must enable log_connections", [resource.name])
}

has_log_connections(flags) {
  flags[_].name == "log_connections"
  flags[_].value == "on"
}

Tip: Lensix runs the sql_pgconnections check continuously across your accounts, so even instances created outside your IaC pipeline, by a console click or an emergency hotfix, get flagged. Treat the CI gate and the runtime scan as complementary layers, not alternatives.


Best practices

  • Enable the full logging set. Pair log_connections with log_disconnections and consider log_statement tuned to ddl so schema changes are recorded without logging every query.
  • Route logs to a sink. Export Cloud SQL logs to a dedicated logging bucket or BigQuery dataset with retention that matches your compliance requirements, often one year or more for regulated data.
  • Use a connection pooler. PgBouncer or Cloud SQL's built-in connection management reduces connection churn, which keeps log volume and cost in check while you still capture meaningful session events.
  • Alert on anomalies. Build log-based metrics for connection spikes, off-hours access, and connections from unexpected source ranges, then wire them into your alerting.
  • Prefer IAM database authentication. Combine connection logging with cloudsql.iam_authentication so connection log lines tie back to a real IAM identity instead of a shared database user.
  • Audit flags regularly. Database flags drift over time as people patch instances. A periodic scan catches the instance someone reconfigured during an incident and forgot to revert.

Connection logging is one of the cheapest security controls you can enable on a Cloud SQL instance, and it is one of the first things you will wish you had turned on the day you need it. Flip the flag, enforce it in your pipeline, and let it run.