How to Fix Azure Database for PostgreSQL Stuck in Starting State When It Keeps Recurring
Second time in a month. The portal is frozen. The CLI returns SeverBusyWithOtherOperation on every command. This guide covers the immediate recovery steps, the support escalation template, and the post-incident hardening that stops this from happening a third time.
Why It Keeps Recurring — This Is Not Normal Behaviour
Asingle occurrence of a PostgreSQL Flexible Server stuck in the Starting state can be written off as a platform transient. The second occurrence within a month on the same server is a signal: something about this server's configuration, workload pattern, or infrastructure placement is making it structurally prone to this class of failure. A support ticket that just asks to "unblock the server" without requesting root cause investigation will result in a third and fourth occurrence.
The SeverBusyWithOtherOperation error means Azure's control plane holds an exclusive lock on the server resource — an internal workflow that never completed cleanly is still marked as running. This lock prevents all new management operations from being accepted. The error text is the same whether the stuck operation was a start, stop, scale, patch, or maintenance event. You cannot distinguish which one caused it from the outside, and you cannot clear it from the portal or CLI.
What makes recurring cases different from a single occurrence is that recurring cases have an identifiable underlying condition that survived the first support fix. The most common recurring triggers are: an active maintenance window that collides with a scheduled stop/start cycle at a consistent weekly cadence; storage approaching capacity that causes WAL accumulation; a burstable (B-series) SKU that repeatedly exhausts CPU credits during startup; or inactive logical replication slots that steadily consume disk space between incidents. None of these clear themselves when Microsoft support force-resets the server state — they must be explicitly addressed.
Stop Immediately — What Not to Do When Stuck
The instinct when a server is stuck is to keep hammering it with stop and start commands. This is the single most damaging thing you can do. Each retry call adds a new failed operation entry to the Azure Activity Log, making the timeline harder for the support engineer to read. In some control-plane implementations, a new failed operation can reset an internal timeout counter, meaning the stuck lock takes longer to clear. Do these things once, capture the output, and then stop.
Triage in 10 Minutes — Confirm the Lock and Collect Evidence
Run these commands once each. The goal is to confirm the stuck state, determine whether a platform incident is involved, and collect the correlation ID that the Microsoft support team needs to locate the specific stuck internal workflow.
Check for an active regional platform incident — 2 minutes
Open azure.status.microsoft.com and look for active incidents affecting Azure Database for PostgreSQL in your region. Also open Service Health in the Azure portal — this shows incidents specific to your subscription. A regional capacity constraint or zonal outage (documented cases include burstable SKU capacity issues in East US and other regions) can cause mass stuck-state events that resolve without any customer action once the incident closes. If you see an active incident, note the incident reference and include it in your support ticket.
Get current server state and collect the Correlation ID
Run the commands below. The most critical output is the Correlation ID from the Activity Log — a GUID that allows the backend team to find the specific stuck workflow instantly. Copy it exactly and save it before opening the ticket.
RG="your-resource-group"
# 1. Get current server state az postgres flexible-server show \
--name "${SERVER}" --resource-group "${RG}" \
--query "{State:state,SKU:sku.name,Version:version,HA:highAvailability.mode}" \
--output json
# 2. Get resource ID for Activity Log query RID=$(az postgres flexible-server show \
--name "${SERVER}" --resource-group "${RG}" \
--query id -o tsv)
# 3. Get Activity Log — COPY THE correlationId FROM THE OUTPUT az monitor activity-log list \
--resource-id "${RID}" --max-events 20 \
--query "[].{Time:eventTimestamp,Op:operationName.value,Status:status.value,CorrelationId:correlationId}" \
--output table
# 4. Attempt stop ONCE — capture the full error, do NOT retry az postgres flexible-server stop \
--name "${SERVER}" --resource-group "${RG}" 2>&1
# Expected error: (SeverBusyWithOtherOperation) Cannot perform 'Stop' server operation...
# 5. Check resource locks (rule out customer-created locks as a factor) az resource lock list \
--resource-name "${SERVER}" \
--resource-group "${RG}" \
--resource-type "Microsoft.DBforPostgreSQL/flexibleServers" \
--output table
Check Resource Health for PlatformInitiated events
Navigate to your PostgreSQL server in the portal → Help → Resource Health. This shows a timeline of availability events including PlatformInitiated downtime entries. Look for any events around the time the server got stuck. Screenshot any PlatformInitiated events — these are additional evidence of a control-plane issue for your support ticket and are especially useful for demonstrating the recurring pattern if a similar event appears on both the first and second occurrence dates.
Run built-in diagnostics — saves support back-and-forth
Navigate to your server → Help → Diagnose and solve problems. Search for and run Availability and Connectivity and Long-Running Operations if available. Screenshot the results. These diagnostics sometimes surface hidden control-plane operations not visible in the Activity Log, and including them in your support ticket reduces the number of follow-up information requests from the support engineer.
Open a Severity A Support Ticket — Recurring Incident Template
Because this is the second occurrence in a month, frame the ticket explicitly as a recurring incident investigation, not just an unblock request. A ticket framed only as "please fix the stuck server" will result in the support engineer clearing the lock and closing the ticket — which is exactly what happened after the first occurrence, and it did not prevent the second. A ticket framed as a recurring incident investigation triggers a different internal workflow where the engineer is expected to identify and document the root cause, not just restore service.
in Starting — SeverBusyWithOtherOperation blocks all management operations
SEVERITY: A — Production database unavailable, second occurrence in 1 month
== SERVER DETAILS ==
Server name: psql-xxx
Resource group: [your-rg]
Subscription ID: [your-subscription-id]
Region: [e.g. West Europe]
SKU / tier: [e.g. Standard_B2ms Burstable / Standard_D4ds_v5 General Purpose]
PostgreSQL version: [e.g. 16]
High Availability: Enabled / Disabled
Read replicas: Yes / No
== CURRENT STATE ==
Provisioning state: Starting (stuck)
Stuck since: [timestamp UTC]
Impact: Database connections all failing, applications unavailable
== THIS IS A RECURRING INCIDENT ==
First occurrence date: [date ~1 month ago]
First occurrence resolution: Resolved by [support/platform team] — no root cause shared
Second occurrence date: [today's date]
Time between incidents: approximately 30 days
Pattern: same error, same server, same SeverBusyWithOtherOperation behaviour
== KEY EVIDENCE (CORRELATION IDs) ==
Activity Log — Correlation ID of stuck operation: [PASTE GUID]
Activity Log — Operation name: [e.g. "Start server"]
Activity Log — Timestamp: [e.g. 2026-07-08T08:19:00Z]
Resource Health — PlatformInitiated event: [Yes/No — paste details if yes]
Activity Log — No InProgress events visible: [Yes/No]
== EXACT CLI ERROR ==
(SeverBusyWithOtherOperation) Cannot perform 'Stop' server operation because
server 'psql-xxx' is busy processing other operation.
Code: SeverBusyWithOtherOperation
Message: Cannot perform 'Stop' server operation because server 'psql-xxx'
is busy processing other operation.
== WHAT WE TRIED ==
- az postgres flexible-server stop: SeverBusyWithOtherOperation
- Portal Stop button: greyed out
- Resource locks: none (az resource lock list returns empty)
- Did NOT retry to avoid adding noise to Activity Log
== REQUESTS (BOTH REQUIRED FOR RECURRING CASE) ==
1. Immediate: Clear the stuck backend operation and restore server to stable state
2. Investigation: Identify the root cause of this recurring pattern — why has
the same server got stuck twice in 30 days?
3. Documentation: Share the root cause finding with us so we can take
preventive action on our side
4. Recommendation: Advise on server configuration, SKU, or maintenance window
changes to prevent a third occurrence
Emergency Recovery via PITR — If You Cannot Wait for Support
If your database is production-critical and waiting for Microsoft support to respond (typically 1–4 hours for Severity A) is not acceptable, you can initiate a Point-in-Time Restore (PITR) to create a new server from a recent backup. This gives you a working database quickly while support resolves the original stuck server in the background. Note that the restored server has a different hostname — connection strings must be updated across all applications.
If the PITR restore attempt itself fails with LocationRestricted or management errors, this means the control-plane lock is also blocking restore operations. Include this failure in your support ticket — it signals that the lock is more pervasive than a simple stuck workflow and requires a higher-priority internal escalation.
--name "${SERVER}" --resource-group "${RG}" \
--query "{EarliestRestore:earliestRestoreDate,SKU:sku.name}" \
--output json
# Restore to a new server — use a timestamp you know was before the stuck state # Adjust --restore-time to a safe point (e.g. last known good state) az postgres flexible-server restore \
--name "${SERVER}-recovery" \
--resource-group "${RG}" \
--source-server "${SERVER}" \
--restore-time "2026-07-08T07:00:00Z" \
--sku-name "Standard_D4ds_v5" \
--tier "GeneralPurpose"
# If restore fails with LocationRestricted or SeverBusyWithOtherOperation: # Add this note to your support ticket — lock is deeper than a simple stuck workflow # Request backend-initiated restore and document the PITR failure as additional evidence
The Six Root Causes Behind Recurring Stuck States
These are the confirmed root causes from documented Microsoft Q&A resolutions, support case histories, and the Azure PostgreSQL engineering blog. A recurring incident almost always involves one of these. Ask your support engineer explicitly which of these was identified for your server — and if they cannot confirm, request backend log evidence before closing the ticket.
| Root Cause | How to Detect | Fix to Request / Apply |
|---|---|---|
| Platform maintenance window collision Azure background maintenance runs concurrently with a customer-triggered start/stop | Resource Health shows PlatformInitiated events at the same timestamp as the stuck state. Both incidents happened at similar times of day or week. | Configure a dedicated maintenance window in the portal at a time that does not overlap with any automation or peak usage windows. Request support confirm whether platform maintenance triggered both incidents. |
| Storage full — WAL accumulation from inactive replication slots PostgreSQL retains WAL for inactive logical replication slots until disk is full | Storage metrics at or near 100% before the stuck event. Log entries referencing "no space left on device". Support backend confirmed WAL accumulation in prior resolved cases. | Enable Auto Storage Growth in Compute + Storage settings. Drop or monitor inactive replication slots. Enable storage alert at 75%. |
| CPU credit exhaustion (burstable B-series SKU) B-series VMs accumulate CPU credits when idle; startup requires credit balance | Server SKU is Standard_B*ms. CPU credits metric was at zero or near-zero when the start was attempted. Previous incident also on a B-series SKU. | Upgrade to a General Purpose (D-series) SKU — dedicated vCores, no credit model, more reliable for start sequences. Do not use burstable SKUs for databases that need reliable starts. |
| 7-day auto-start collision with automation Azure auto-starts a stopped server after 7 days, colliding with customer automation | Incidents separated by approximately 7-day multiples. Server is stopped regularly and incidents occur on the expected auto-start day. | Ensure automation start commands include a pre-check for server state. Schedule automation slightly after the expected auto-start window. Consider upgrading to a non-stopped operational model. |
| Zonal outage or regional capacity constraint Azure regional infrastructure issue affecting specific SKU families or AZs | Active Azure Status incident in your region. Multiple customers reporting the same issue simultaneously. SKU type matches the affected family (e.g. burstable in East US). | Nothing customer-side can accelerate recovery. Monitor Azure Status. Consider Availability Zone redundant deployment if the region supports it, to survive single-AZ failures. |
| Corrupted internal metadata or expired SAS key Backend storage access credentials or configuration files fail silently during start | No obvious customer-side cause. Support backend investigation found a reserved space file or expired SAS key. Recurring at irregular intervals. | This requires backend mitigation only — the support team must reset the SAS key or remove the corrupt file. Request that support confirm whether this was the root cause and verify it has been resolved for both occurrences. |
Post-Incident Hardening Checklist — Stop the Third Occurrence
After the server is restored to a stable state, do not simply restart operations. Work through this checklist before declaring the incident closed. Every item addresses a confirmed recurrence trigger.
-- Run this FIRST after the server recovers
SELECT
slot_name,
plugin,
active,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots
ORDER BY retained_wal DESC;
-- If any slot shows active = false AND retained_wal is large: -- DROP REPLICATION SLOT 'slot_name_here'; -- This reclaims the retained WAL space immediately
-- Also check current disk usage SELECT
datname,
pg_size_pretty(pg_database_size(datname)) AS db_size
FROM pg_database
ORDER BY pg_database_size(datname) DESC;
Monitoring Setup — Alert Before the Next Stuck State Happens
The right time to find out your PostgreSQL server is stuck is not when applications start failing — it is within minutes of the server entering a transitional state. These monitoring configurations alert before users are impacted.
RG="your-resource-group"
EMAIL="ops-team@yourdomain.com"
SUBSCRIPTION="your-subscription-id"
# Get the server resource ID RID=$(az postgres flexible-server show --name "${SERVER}" --resource-group "${RG}" --query id -o tsv)
# Create an Action Group for email alerting az monitor action-group create \
--resource-group "${RG}" \
--name "pg-alert-group" \
--short-name "pgalert" \
--action email ops-email "${EMAIL}"
AG_ID=$(az monitor action-group show --resource-group "${RG}" --name "pg-alert-group" --query id -o tsv)
# Alert 1: Storage utilisation above 75% (early warning before disk full) az monitor metrics alert create \
--name "pg-storage-high" \
--resource-group "${RG}" \
--scopes "${RID}" \
--condition "avg storage_percent > 75" \
--window-size 5m \
--evaluation-frequency 5m \
--severity 2 \
--action "${AG_ID}" \
--description "PostgreSQL storage above 75% — risk of stuck start on next restart"
# Alert 2: Activity Log alert when server Start/Stop operation begins # This fires when the operation is accepted — gives you early visibility az monitor activity-log alert create \
--name "pg-start-stop-activity" \
--resource-group "${RG}" \
--scope "${RID}" \
--condition "category=Administrative and operationName=Microsoft.DBforPostgreSQL/flexibleServers/start/action" \
--action-group "${AG_ID}" \
--description "PostgreSQL start operation triggered — monitor for stuck state"
# Alert 3: CPU credits remaining (for burstable SKUs only) # If credits drop to zero, next start may hang az monitor metrics alert create \
--name "pg-cpu-credits-low" \
--resource-group "${RG}" \
--scopes "${RID}" \
--condition "avg cpu_credits_remaining < 10" \
--window-size 5m \
--evaluation-frequency 5m \
--severity 2 \
--action "${AG_ID}" \
--description "CPU credits critically low — consider upgrading to General Purpose SKU"
Key Takeaways
Related FAVRITE Articles
- How to Fix Azure Database for PostgreSQL Flexible Server Stuck in Starting State: Step-by-Step Guide
- How to Handle NT AUTHORITY\SYSTEM in Azure SQL Managed Instance After an On-Premises Restore
- Least Privileged Access Required to View Azure App Service Log Stream
- Top 50 Azure Cloud Administrator Interview Questions and Answers