Back to blog
Best PracticesCloud SecurityDatabasesGCPMonitoring & Logging

PostgreSQL Temp File Logging Disabled on Cloud SQL

Learn why log_temp_files matters on GCP Cloud SQL PostgreSQL, how disk spills hurt performance and security, and how to enable and enforce the flag.

TL;DR

This check flags Cloud SQL PostgreSQL instances where the log_temp_files flag is unset or disabled, leaving you blind to disk-spilling queries. Set the flag to 0 to log every temporary file and surface inefficient or abusive queries before they hurt performance.

PostgreSQL writes temporary files to disk when a query needs more working memory than work_mem allows. Sorts, hash joins, and large aggregations are common culprits. By default, Cloud SQL does not log these events, so you have no record of which queries are spilling to disk, how often, or how large the spills are. This Lensix check, sql_pgtempfiles, looks at the log_temp_files database flag on your GCP Cloud SQL PostgreSQL instances and reports any instance where it is not enabled.


What this check detects

The check inspects the database flags on each Cloud SQL PostgreSQL instance and verifies that log_temp_files is present and set to a value that logs temporary file usage. The flag controls a threshold, measured in kilobytes:

  • -1 (the default) disables temporary file logging entirely.
  • 0 logs every temporary file regardless of size.
  • Any positive integer logs only temporary files at or above that size in KB.

If the flag is missing or set to -1, the check fails. The recommended secure value is 0, which captures all temporary file activity.

Note: A temporary file is not the same as a temporary table. log_temp_files records the on-disk files PostgreSQL creates when an operation exceeds work_mem. Each logged line includes the file path and its size, which together tell you exactly which query overflowed and by how much.


Why it matters

Temporary file logging is one of those settings that looks like pure performance tuning until you need it during an incident. Here is why it earns a place in your security and reliability baseline.

Disk spills are a silent performance killer

When a query spills to disk, it stops using fast memory and starts hitting storage. On a busy instance this can multiply query latency, exhaust IOPS, and cascade into connection pile-ups. Without logging, you find out about it through user complaints and guesswork rather than data. With logging on, you have a precise record of which statements caused the spill and the size of each file.

It exposes inefficient and abusive queries

Repeated large temporary files often point to a missing index, an unbounded ORDER BY, or a query pulling far more rows than it should. They can also signal a query crafted to consume resources, whether by accident from a bad deploy or deliberately as part of a denial-of-service attempt against your database. Temporary file logs make these patterns visible.

It supports compliance and audit requirements

Benchmarks such as the CIS Google Cloud Platform Foundations Benchmark call out database logging flags explicitly. Auditors expect to see evidence that you can reconstruct database activity, and temporary file logs are part of a complete logging posture alongside log_connections, log_disconnections, and log_min_duration_statement.

Warning: Setting log_temp_files to 0 on a high-traffic instance with many small spills can generate a large volume of log lines. This increases Cloud Logging ingestion, which has a cost. If volume becomes a problem, raise the threshold to a value like 1024 (1 MB) to capture only meaningful spills, but be aware this is a compromise rather than full coverage.


How to fix it

You can enable the flag through the gcloud CLI, the Google Cloud console, or infrastructure as code. Pick whichever matches how you manage the instance.

Warning: Changing a database flag on Cloud SQL may require a restart depending on the flag. log_temp_files is a reloadable flag and does not force a restart on its own, but applying it through gcloud sql instances patch can still trigger a brief maintenance operation. Apply changes during a low-traffic window if you are uncertain.

Option 1: gcloud CLI

First, check the current flags so you do not accidentally drop existing ones. The --database-flags argument replaces the entire flag set on each call.

gcloud sql instances describe INSTANCE_NAME \
  --project PROJECT_ID \
  --format="value(settings.databaseFlags)"

Then apply log_temp_files=0 alongside any flags you already had. Include every existing flag in the same command:

gcloud sql instances patch INSTANCE_NAME \
  --project PROJECT_ID \
  --database-flags log_temp_files=0,log_min_duration_statement=1000

Danger: --database-flags overwrites the full list of flags. If you omit a flag that was previously set, it reverts to its default. Always copy the existing flags from the describe output into your patch command, or you risk silently disabling other security and logging settings.

Option 2: Google Cloud console

  1. Open SQL in the Google Cloud console and select your PostgreSQL instance.
  2. Click Edit.
  3. Expand Flags.
  4. Click Add a database flag, choose log_temp_files, and set the value to 0.
  5. Click Save and confirm.

Option 3: Terraform

If you manage Cloud SQL with Terraform, add the flag to the instance settings block. This makes the configuration durable and reviewable.

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

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

    database_flags {
      name  = "log_temp_files"
      value = "0"
    }

    database_flags {
      name  = "log_min_duration_statement"
      value = "1000"
    }
  }
}

Apply it with the usual workflow:

terraform plan -out tfplan
terraform apply tfplan

Tip: In Terraform, each database_flags block is additive, so you do not have the overwrite problem you get with the gcloud CLI. Keep all flags declared in the same resource and let Terraform reconcile the full set.

Verify the change

Confirm the flag took effect, then generate some load and check Cloud Logging for the new entries.

gcloud sql instances describe INSTANCE_NAME \
  --project PROJECT_ID \
  --format="value(settings.databaseFlags)" | grep log_temp_files

Temporary file events appear in the PostgreSQL logs with a message like temporary file: path "...", size NNNN. You can query them in Cloud Logging:

gcloud logging read \
  'resource.type="cloudsql_database" AND textPayload:"temporary file"' \
  --project PROJECT_ID \
  --limit 20

How to prevent it from happening again

Fixing one instance by hand is fine. Stopping the misconfiguration from reappearing across dozens of instances is the real goal. Bake the flag into the way you provision and review databases.

Make it a module default

If you use a shared Terraform module for Cloud SQL, set the logging flags inside the module so every instance inherits them. Teams provisioning a new database get the secure baseline without thinking about it.

variable "extra_database_flags" {
  type    = map(string)
  default = {}
}

locals {
  base_flags = {
    log_temp_files             = "0"
    log_min_duration_statement = "1000"
    log_connections            = "on"
    log_disconnections         = "on"
  }
  all_flags = merge(local.base_flags, var.extra_database_flags)
}

Gate it in CI/CD with policy as code

Catch missing flags before they ever reach production by validating Terraform plans in your pipeline. An Open Policy Agent (Conftest) rule can reject any Cloud SQL PostgreSQL instance without temporary file logging:

package main

deny[msg] {
  rc := input.resource_changes[_]
  rc.type == "google_sql_database_instance"
  startswith(rc.change.after.database_version, "POSTGRES")

  flags := { f.name: f.value |
    f := rc.change.after.settings[_].database_flags[_]
  }

  not flags["log_temp_files"]
  msg := sprintf("%s is missing log_temp_files flag", [rc.address])
}

Run it against a plan in JSON form during the pull request:

terraform show -json tfplan > plan.json
conftest test plan.json --policy policy/

Tip: Pair the CI gate with continuous checks in Lensix so drift is caught even when changes happen outside your pipeline. A console edit or an emergency gcloud command can quietly remove the flag, and only ongoing scanning will flag it again.


Best practices

Temporary file logging works best as part of a broader logging and observability baseline for PostgreSQL on Cloud SQL.

  • Enable a full set of logging flags. Combine log_temp_files=0 with log_min_duration_statement, log_connections=on, log_disconnections=on, log_checkpoints=on, and log_lock_waits=on for a complete picture of activity.
  • Tune work_mem deliberately. Once you can see which queries spill, decide whether to raise work_mem for the workload, optimize the query, or add an index. Logging without action just fills storage.
  • Alert on spill volume. Create a log-based metric in Cloud Monitoring counting temporary file events and alert when the rate spikes. A sudden jump often correlates with a bad deploy or a runaway report.
  • Review log retention and cost. Decide how long you keep these logs and route high-volume entries to a sink such as BigQuery or Cloud Storage if you need long retention without paying for hot logging storage.
  • Apply the same baseline to read replicas. Flags do not always propagate the way you expect. Confirm replicas carry the same logging configuration as the primary.

The flag itself is a one-line change, but the value comes from treating temporary file logs as a signal you actually monitor. Turn it on, build an alert around it, and you convert an invisible class of performance and abuse problems into something you can see and act on.