Back to blog
AzureCloud SecurityDatabasesMonitoring & LoggingOperations & Compliance

PostgreSQL Log Retention Too Short on Azure: Why It Matters and How to Fix It

Azure PostgreSQL servers with log retention under 7 days leave you blind during incidents. Learn why it matters and how to fix it with CLI, Terraform, and policy.

TL;DR

This check flags Azure Database for PostgreSQL servers where the log_retention_days setting is below 7 days, which leaves you blind during incident investigations. Bump it to at least 7 days (or longer for compliance) with a single CLI command.

Logs are the first thing you reach for when something goes wrong. A slow query that started two days ago, a failed login burst overnight, a connection that hung and brought down an app pool. If your PostgreSQL server is throwing those logs away after a day or two, you are debugging blind by the time anyone notices the problem.

Lensix raises PostgreSQL Log Retention Too Short when an Azure Database for PostgreSQL server keeps its logs for fewer than 7 days. This post explains what the setting controls, why a short window hurts you in practice, and how to fix it across the CLI, the portal, and infrastructure as code.


What this check detects

Azure Database for PostgreSQL exposes a server parameter called log_retention_days. It controls how long the server keeps log files generated by PostgreSQL logging before they are rotated out and deleted. When logging is enabled (via parameters like log_checkpoints, log_connections, log_disconnections, and friends), this value determines how far back you can actually look.

The check fails when log_retention_days is set to a value below 7. On a Single Server, the default is often 3 days, which is short enough to trip the check out of the box.

Note: There are two flavors of this service. Azure Database for PostgreSQL Single Server uses the log_retention_days server parameter directly. Flexible Server pushes server logs to Azure Monitor or stores them on disk, so retention is typically governed by diagnostic settings and Log Analytics workspace retention. This check targets the server-side log retention parameter on Single Server style configurations.


Why it matters

Log retention is one of those settings that costs nothing to get right and a lot to get wrong, because you only notice the problem at the worst possible moment.

Incident investigation goes cold

Most breaches and outages are not detected the instant they happen. Industry reports consistently put the average time to even identify an incident in the range of weeks, not hours. If your database keeps three days of logs, the evidence of how an attacker got in, what queries they ran, or which credentials were abused is already gone by the time anyone starts looking.

You lose your audit trail

Connection and disconnection logs tell you who connected, from where, and when. Without them you cannot answer basic questions during a security review:

  • Did this service account log in from an unexpected IP?
  • When did the brute force attempt against the admin user start?
  • Which application was holding the connections that exhausted the pool last weekend?

Compliance frameworks expect more

Standards like PCI DSS, HIPAA, SOC 2, and ISO 27001 all expect retained audit logs, frequently with minimums measured in months or longer. A 3 day window will not pass an audit. Even where 7 days satisfies the minimum, you usually want logs shipped to long term storage to meet the full requirement.

Warning: Setting log_retention_days higher keeps logs on the server, but it does not replace centralized log collection. Server-local logs disappear if the server is deleted or fails over. Treat this parameter as a floor, and ship logs to a Log Analytics workspace or storage account for anything you need beyond the short term.


How to fix it

The fix is to raise log_retention_days to at least 7. Pick a higher number if your compliance posture calls for it.

Option 1: Azure CLI

For a Single Server, update the server parameter directly:

az postgres server configuration set \
  --resource-group my-resource-group \
  --server-name my-postgres-server \
  --name log_retention_days \
  --value 7

Confirm the change took effect:

az postgres server configuration show \
  --resource-group my-resource-group \
  --server-name my-postgres-server \
  --name log_retention_days \
  --query "value" -o tsv

While you are in there, make sure logging itself is actually turned on so retention has something to retain:

az postgres server configuration set \
  --resource-group my-resource-group \
  --server-name my-postgres-server \
  --name log_connections \
  --value on

az postgres server configuration set \
  --resource-group my-resource-group \
  --server-name my-postgres-server \
  --name log_disconnections \
  --value on

Option 2: Azure Portal

  1. Open your PostgreSQL server in the Azure Portal.
  2. Under Settings, select Server parameters.
  3. Search for log_retention_days.
  4. Set the value to 7 or higher.
  5. Click Save.

Note: This is a dynamic parameter on PostgreSQL Single Server, so changing it does not require a server restart. The new retention window applies going forward.

Option 3: Terraform

If you manage the server with Terraform, define the parameter so the change is tracked in code and cannot drift back:

resource "azurerm_postgresql_configuration" "log_retention" {
  name                = "log_retention_days"
  resource_group_name = azurerm_resource_group.main.name
  server_name         = azurerm_postgresql_server.main.name
  value               = "7"
}

resource "azurerm_postgresql_configuration" "log_connections" {
  name                = "log_connections"
  resource_group_name = azurerm_resource_group.main.name
  server_name         = azurerm_postgresql_server.main.name
  value               = "on"
}

Option 4: Flexible Server with Azure Monitor

On Flexible Server, route logs to a Log Analytics workspace and control retention there instead. Create a diagnostic setting:

az monitor diagnostic-settings create \
  --name pg-logs-to-law \
  --resource $(az postgres flexible-server show \
      --resource-group my-resource-group \
      --name my-flexible-server --query id -o tsv) \
  --workspace my-log-analytics-workspace \
  --logs '[{"category":"PostgreSQLLogs","enabled":true}]'

Then set retention on the workspace table to meet your policy, for example 30 days:

az monitor log-analytics workspace table update \
  --resource-group my-resource-group \
  --workspace-name my-log-analytics-workspace \
  --name AzureDiagnostics \
  --retention-time 30

Tip: Sending logs to a Log Analytics workspace also unlocks KQL queries and alerting. You can build an alert that fires on repeated failed authentications or a sudden spike in connection volume, which turns passive logs into active detection.


How to prevent it from happening again

Fixing one server is fine. Making sure no new server ships with a 3 day window is what actually moves the needle.

Azure Policy

Use a custom Azure Policy to audit or deny PostgreSQL servers with a short retention window. A policy definition that audits the parameter looks like this:

{
  "if": {
    "allOf": [
      {
        "field": "type",
        "equals": "Microsoft.DBforPostgreSQL/servers/configurations"
      },
      {
        "field": "name",
        "equals": "log_retention_days"
      },
      {
        "field": "Microsoft.DBforPostgreSQL/servers/configurations/value",
        "less": "7"
      }
    ]
  },
  "then": {
    "effect": "audit"
  }
}

Assign it at the subscription or management group level so every server is checked continuously. Start with audit to find existing offenders, then move to deny once the estate is clean.

CI/CD gates for infrastructure as code

Catch the misconfiguration before it ever reaches Azure. If you use Terraform, run a policy-as-code scan on every pull request. A Checkov or Conftest rule can fail the build when log_retention_days is missing or too low. Here is a small OPA Rego example for Conftest:

package main

deny[msg] {
  resource := input.resource.azurerm_postgresql_configuration[name]
  resource.name == "log_retention_days"
  to_number(resource.value) < 7
  msg := sprintf("PostgreSQL log_retention_days is %s, must be >= 7", [resource.value])
}

Tip: Let Lensix run the continuous check across all your subscriptions so you catch servers created outside your IaC pipeline, manual portal changes, and drift that policy assignments miss. The CI gate stops new mistakes, and ongoing scanning catches the ones that slip in anyway.


Best practices

  • Treat 7 days as the absolute minimum. It satisfies this check, but most teams should keep operationally useful logs for 30 days and audit logs far longer.
  • Centralize, do not just retain. Ship logs to a Log Analytics workspace or storage account so they survive server deletion and failover.
  • Turn on the logging that matters. Retention is meaningless if log_connections, log_disconnections, and log_checkpoints are off. Enable them together.
  • Match retention to compliance. Map your retention numbers to the actual frameworks you answer to rather than guessing.
  • Alert on the logs. Logs you never read only help after the fact. Build alerts for failed logins, connection spikes, and unusual source IPs.
  • Plan for migration. Single Server is being retired, so factor the move to Flexible Server into your roadmap and design diagnostic settings around Azure Monitor from the start.

Log retention is cheap insurance. A short window saves nothing meaningful and quietly removes your ability to answer questions when it counts most. Set it to at least 7 days, ship logs somewhere durable, and put a policy gate in front of new servers so the setting stays correct.

Fix Azure PostgreSQL Short Log Retention | Lensix | Lensix