Back to blog
AzureBest PracticesCloud SecurityDatabasesReliability

PostgreSQL Storage Auto-Growth Disabled on Azure: Why It Matters and How to Fix It

Disabled storage auto-growth on Azure PostgreSQL can take your database read-only when the disk fills. Learn why it matters and how to enable it fast.

TL;DR

This check flags Azure Database for PostgreSQL servers that have storage auto-growth turned off, which means the database can hit its storage ceiling and go read-only without warning. Enable auto-growth so storage scales up automatically before you run out of space.

Running out of disk space on a managed database is one of those problems that feels almost too basic to worry about, right up until it takes down your production workload at 2 AM. On Azure Database for PostgreSQL, storage is provisioned as a fixed allocation, and when that allocation fills up the server stops accepting writes. Storage auto-growth is the safety valve that prevents this, and this Lensix check makes sure it is actually enabled.

This post walks through what the postgresql_noautogrowth check looks for, why a disabled auto-growth setting is riskier than it sounds, and how to fix and prevent it across the CLI, the portal, and infrastructure as code.


What this check detects

The check inspects each Azure Database for PostgreSQL server in your subscription and reports any server where the storage auto-growth property is set to Disabled. When auto-growth is off, the storage allocated to your server is a hard cap. The database will use exactly what you provisioned and not a byte more, even if there is plenty of headroom in your subscription quota.

Note: This applies to the Single Server deployment model, where the property is called storageAutogrow. On Flexible Server, the equivalent setting is storage.autoGrow. Both control the same behavior: whether Azure automatically expands storage as you approach the limit. Single Server is being retired, so if you are still on it this is also a good moment to plan a migration to Flexible Server.

When auto-growth is enabled, Azure monitors free space and grows the disk in increments once usage crosses a threshold (roughly the larger of 5 GB or 10 percent of allocated storage remaining). The growth happens online, with no downtime and no manual intervention.


Why it matters

The failure mode here is specific and unforgiving. When a PostgreSQL server with auto-growth disabled fills its storage, Azure switches the server into a read-only state. Reads continue to work, but every write, every INSERT, UPDATE, and DELETE, fails. For most applications that means a hard outage, because almost nothing useful happens without writes.

What makes this worse than a typical capacity problem is the recovery path. You cannot just delete some rows to free up space, because deletes are writes too, and the server is rejecting writes. You are forced to scale up the storage tier manually before the database becomes usable again, and storage scaling on Single Server can take time. During that window your application is effectively down.

A storage-full event on PostgreSQL is one of the few database incidents where the obvious fix, deleting data, is the one thing you cannot do.

A few real-world scenarios where this bites teams:

  • Gradual organic growth. The database was provisioned with comfortable headroom two years ago. Usage crept up quietly and nobody re-checked the numbers. The disk fills on an ordinary Tuesday.
  • Unexpected write spikes. A batch job, a data import, or a sudden traffic surge generates far more data than usual and burns through the remaining space in hours.
  • Runaway logging or bloat. Table bloat from heavy update workloads, or an unrotated audit table, consumes space faster than anyone expects.
  • WAL accumulation. A stalled replication slot or a long-running transaction can cause write-ahead logs to pile up and eat storage.

Auto-growth does not solve the underlying cause in every case, but it buys you time. Instead of an outage, you get a larger disk and a chance to investigate during business hours.

Warning: Auto-growth increases your storage, and storage is billed by the GB. A runaway process can cause your disk, and therefore your bill, to grow significantly before you notice. Auto-growth should always be paired with storage usage alerts so that growth never happens silently.


How to fix it

Enabling auto-growth is an online operation. It does not require a restart and does not interrupt connections.

Azure CLI (Single Server)

First, confirm the current state:

az postgres server show \
  --resource-group my-rg \
  --name my-pg-server \
  --query "storageProfile.storageAutogrow" \
  --output tsv

If it returns Disabled, enable it:

az postgres server update \
  --resource-group my-rg \
  --name my-pg-server \
  --set storageProfile.storageAutogrow=Enabled

Azure CLI (Flexible Server)

For the Flexible Server deployment model, the parameter is different:

az postgres flexible-server update \
  --resource-group my-rg \
  --name my-pg-flex \
  --storage-auto-grow Enabled

Azure Portal

  1. Open your PostgreSQL server in the Azure Portal.
  2. Under Settings, select Compute + storage (Flexible Server) or Pricing tier (Single Server).
  3. Find the Storage Auto-growth toggle and set it to Enabled.
  4. Click Save.

Tip: Loop over every server in a subscription in one pass to remediate fleet-wide:

az postgres server list --query "[].{rg:resourceGroup, name:name}" -o tsv | \
while read rg name; do
  az postgres server update --resource-group "$rg" --name "$name" \
    --set storageProfile.storageAutogrow=Enabled
done

Fixing it in infrastructure as code

If you manage Azure with Terraform or Bicep, set auto-growth in the resource definition so it stays enabled through every redeploy.

Terraform (Flexible Server)

resource "azurerm_postgresql_flexible_server" "main" {
  name                = "my-pg-flex"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location

  storage_mb        = 32768
  auto_grow_enabled = true

  sku_name = "GP_Standard_D2s_v3"
  version  = "15"

  administrator_login    = "pgadmin"
  administrator_password = var.pg_admin_password
}

Terraform (Single Server)

resource "azurerm_postgresql_server" "main" {
  name                = "my-pg-server"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location

  sku_name          = "GP_Gen5_2"
  storage_mb        = 51200
  auto_grow_enabled = true

  administrator_login          = "pgadmin"
  administrator_login_password = var.pg_admin_password
  version                      = "11"
  ssl_enforcement_enabled      = true
}

Bicep (Flexible Server)

resource pgServer 'Microsoft.DBforPostgreSQL/flexibleServers@2023-03-01-preview' = {
  name: 'my-pg-flex'
  location: location
  sku: {
    name: 'Standard_D2s_v3'
    tier: 'GeneralPurpose'
  }
  properties: {
    version: '15'
    storage: {
      storageSizeGB: 32
      autoGrow: 'Enabled'
    }
    administratorLogin: 'pgadmin'
    administratorLoginPassword: pgAdminPassword
  }
}

How to prevent it from happening again

Remediating once is fine, but a new server provisioned next month will start the cycle over. Bake the requirement into the places where servers get created.

Azure Policy

Azure Policy can audit or deny PostgreSQL servers that do not have auto-growth enabled. Here is an audit policy for Flexible Server that flags noncompliant resources:

{
  "if": {
    "allOf": [
      {
        "field": "type",
        "equals": "Microsoft.DBforPostgreSQL/flexibleServers"
      },
      {
        "field": "Microsoft.DBforPostgreSQL/flexibleServers/storage.autoGrow",
        "notEquals": "Enabled"
      }
    ]
  },
  "then": {
    "effect": "audit"
  }
}

Switch the effect from audit to deny once you are confident every existing server is compliant, so noncompliant servers cannot be created at all.

Warning: Roll out deny policies carefully. If you flip to deny before remediating existing resources, you can block legitimate redeployments and updates of servers that were created earlier. Start in audit mode, fix what shows up, then enforce.

CI/CD gates

If your infrastructure flows through pull requests, catch the misconfiguration before it merges. Tools like Checkov and tfsec can scan Terraform plans in your pipeline. A simple Checkov run in a GitHub Actions step looks like this:

pip install checkov
checkov -d ./infra --framework terraform

You can also write a custom policy that asserts auto_grow_enabled = true on every PostgreSQL resource and fails the build otherwise.

Tip: Lensix runs the postgresql_noautogrowth check continuously across your subscriptions, so even servers created outside your IaC pipeline, by a portal click or a one-off script, get flagged. Pair the continuous scan with an Azure Policy deny rule and you cover both the detection and prevention sides.


Best practices

Auto-growth is a safety net, not a substitute for capacity planning. Use it alongside these habits:

  • Set storage alerts. Configure Azure Monitor alerts on the storage_percent metric at 75 and 90 percent. Auto-growth handles the immediate emergency, but an alert tells you something is consuming space and gives you a chance to investigate.
  • Watch for table and index bloat. Heavy update and delete workloads leave dead tuples behind. Tune autovacuum and run periodic checks so bloat does not silently inflate your storage footprint.
  • Monitor replication slots. An inactive replication slot prevents WAL from being recycled and can fill a disk surprisingly fast. Drop slots you no longer need.
  • Right-size from the start. Auto-growth only grows, it never shrinks. Provisioning a sensible baseline keeps you from over-paying after a one-time spike pushes storage up permanently.
  • Review growth events. Treat each auto-growth event as a signal worth a quick look. Predictable, gradual growth is healthy. Sudden jumps usually point to a problem worth fixing at the source.
  • Plan your Single Server migration. Azure Database for PostgreSQL Single Server is retiring. Flexible Server has better storage scaling, more configuration control, and a longer support horizon. If you are still on Single Server, factor the migration into your roadmap.

The cost of enabling auto-growth is effectively zero. The cost of leaving it disabled is a write-blocking outage that is painful and slow to recover from. This is one of the cheapest reliability wins available on managed PostgreSQL, so there is rarely a good reason to leave it off.