Back to blog
AzureCloud SecurityDatabasesMonitoring & LoggingOperations & Compliance

PostgreSQL Connection Logging Disabled on Azure

Learn why disabled connection logging on Azure PostgreSQL leaves you blind during incidents, and how to enable log_connections with CLI, Terraform, and policy.

TL;DR

This check flags Azure Database for PostgreSQL servers where the log_connections parameter is off, which means successful logins are never recorded. Turn it on with a single az postgres server configuration set command so you can audit who connected, when, and from where.

Connection logging is one of those settings that nobody misses until an incident is already underway. When a managed PostgreSQL server has log_connections disabled, every successful authentication to the database passes by silently. There is no record of which accounts logged in, what IP they came from, or when the session opened. For a database that often holds your most sensitive data, that is a meaningful gap in your audit trail.

The Lensix check postgresql_nologconnections looks at the server-level parameters on each Azure Database for PostgreSQL instance and reports any server where the log_connections setting is not enabled.


What this check detects

Azure Database for PostgreSQL (both Single Server and Flexible Server) exposes the standard PostgreSQL server parameters, including log_connections. When this parameter is set to on, PostgreSQL writes a log line for each successful connection. The line includes the database user, the client address, and the database name.

This check fails when:

  • A PostgreSQL server exists in the subscription, and
  • Its log_connections parameter is set to off (the default on some configurations).

Note: log_connections only records the establishment of a session. Its companion parameter log_disconnections records when sessions end and how long they lasted. The two are usually enabled together to get a complete picture of session activity.


Why it matters

A database without connection logs is hard to investigate after the fact. Consider a few situations where this gap bites:

  • Credential theft. An attacker obtains an application database password from a leaked config file or a compromised CI runner. With connection logging off, you have no record that an unfamiliar IP started using those credentials at 3am.
  • Insider activity. A developer with broad access connects to production directly rather than going through an approved tool. Without logs, that connection leaves no footprint.
  • Incident scoping. When you do detect a breach through another signal, the first question is always "what else did they touch?" Connection logs let you build a timeline. Without them, you are guessing.

There is also a compliance angle. Frameworks such as PCI DSS, SOC 2, HIPAA, and ISO 27001 all expect that access to systems holding regulated data is logged and reviewable. An auditor who asks for a list of database logins and gets a blank stare is going to write a finding.

Warning: Connection logs increase the volume of data written to your log destination. If you forward logs to Azure Monitor or a Log Analytics workspace, expect a modest bump in ingestion cost on busy servers. This is almost always worth it, but budget for it on high-traffic databases.


How to fix it

The fix is to set log_connections to on. The exact command depends on whether you run Single Server or Flexible Server.

Flexible Server (recommended deployment type)

az postgres flexible-server parameter set \
  --resource-group my-rg \
  --server-name my-pg-server \
  --name log_connections \
  --value on

While you are at it, enable disconnection logging too:

az postgres flexible-server parameter set \
  --resource-group my-rg \
  --server-name my-pg-server \
  --name log_disconnections \
  --value on

Single Server

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

Note: Both log_connections and log_disconnections are dynamic parameters on PostgreSQL, so changing them does not require a server restart. The new setting takes effect for connections opened after the change. Existing sessions keep their original behavior until they reconnect.

From the Azure Portal

  1. Open your PostgreSQL server in the Azure Portal.
  2. Under Settings, select Server parameters.
  3. Search for log_connections.
  4. Set the value to ON.
  5. Repeat for log_disconnections if desired.
  6. Click Save.

Confirm the change

az postgres flexible-server parameter show \
  --resource-group my-rg \
  --server-name my-pg-server \
  --name log_connections \
  --query value -o tsv

You should see on returned.

Tip: Enabling the parameter writes the log lines, but you still need somewhere to send them. Make sure server logs are routed to a Log Analytics workspace or a storage account through a diagnostic setting, otherwise the entries are written and then aged out without ever being queryable.

To wire up that diagnostic setting:

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

Fixing it as code

If you manage infrastructure with Terraform, set the parameter declaratively so it never drifts back to off. For Flexible Server:

resource "azurerm_postgresql_flexible_server_configuration" "log_connections" {
  name      = "log_connections"
  server_id = azurerm_postgresql_flexible_server.main.id
  value     = "on"
}

resource "azurerm_postgresql_flexible_server_configuration" "log_disconnections" {
  name      = "log_disconnections"
  server_id = azurerm_postgresql_flexible_server.main.id
  value     = "on"
}

For Bicep:

resource logConnections 'Microsoft.DBforPostgreSQL/flexibleServers/configurations@2023-06-01-preview' = {
  parent: postgresServer
  name: 'log_connections'
  properties: {
    value: 'on'
    source: 'user-override'
  }
}

How to prevent it from coming back

One-off fixes drift. The goal is to make "logging on" the default that everyone gets without thinking about it.

Azure Policy

Use a built-in or custom Azure Policy to audit (or enforce) the setting across every server in a subscription. Azure ships a built-in policy named "Connection throttling should be enabled for PostgreSQL database servers" and related logging policies. You can also author a custom policy that checks the log_connections configuration value and flags non-compliant servers.

Tip: Assign the policy in Audit mode first to see how many servers are non-compliant, then move to DeployIfNotExists once you are confident the remediation will not surprise anyone. This avoids enforcing a change on a busy production server during peak hours.

CI/CD gate

If your databases are provisioned through Terraform or Bicep, add a check in your pipeline that fails the build when a PostgreSQL resource is defined without the logging configuration. A quick way to do this with Terraform plans is to run a policy-as-code tool like Conftest or Checkov against the plan output.

# Run Checkov against your Terraform before apply
checkov -d ./infra --framework terraform

Continuous monitoring with Lensix

Keep the postgresql_nologconnections check running on a schedule so that any server created outside your IaC pipeline, or any manual parameter change, is caught quickly rather than discovered during an audit months later.


Best practices

  • Enable connection and disconnection logging together. The pair gives you session open and close events plus duration, which is what you actually want during an investigation.
  • Send logs somewhere durable. Route PostgreSQL logs to a Log Analytics workspace with a sensible retention period that matches your compliance requirements.
  • Set alerts, not just storage. Logs you never look at have limited value. Build a query that flags connections from unexpected IP ranges or service accounts logging in from new locations.
  • Pair logging with network controls. Logging tells you who got in. Private endpoints, firewall rules, and Azure AD authentication reduce who can attempt to get in. Use both.
  • Keep logging consistent across environments. Enable the same parameters in staging and dev so behavior matches production and so a real incident in lower environments is also investigable.

Connection logging is cheap insurance. It costs a single parameter change and a bit of ingestion, and it turns "we have no idea who accessed the database" into "here is the exact timeline." Turn it on, enforce it with policy, and move on.