Skip to main content
emnode
Compliance Low severity MCSB LT-6

Microsoft Defender for Cloud · Azure SQL Database

Audit retention for SQL servers should be set to at least 90 days

Written and reviewed by Emnode · Last reviewed

What does the recommendation "Audit retention for SQL servers should be set to at least 90 days" check?

Flags any Azure SQL logical server whose server-level auditing writes to a storage account but keeps those audit logs for fewer than 90 days, by reading the 'retentionDays' value on the server auditing settings. The check only covers auditing whose destination is a storage account: a retention value of zero means logs are kept indefinitely and passes, while any positive value below 90 fails. It does not evaluate auditing sent to Log Analytics or Event Hubs (those have no per-destination retention day setting here), does not check database-level audit policies, and does not verify that auditing is enabled at all, that is a separate recommendation.

Why does "Audit retention for SQL servers should be set to at least 90 days" matter?

SQL audit logs are the record of who connected, what they queried and which permissions changed. Intrusions and insider misuse are routinely discovered weeks or months after the fact, and the median dwell time for an attacker is well beyond a few days. If storage retention is set to 30 days, the evidence you need to scope a breach, prove what data was touched and satisfy a regulator has already been deleted by the time you start looking. Short retention also breaks compliance frameworks such as PCI DSS and many internal audit mandates that require at least 90 days of immediately available log history, turning a forensic gap into a finding.

How do I fix "Audit retention for SQL servers should be set to at least 90 days"?

  1. Set retention to at least 90 days on the server audit policy: az sql server audit-policy update --resource-group <rg> --name <server> --state Enabled --blob-storage-target-state Enabled --storage-account <storage> --retention-days 90.
  2. In Bicep or ARM, set the 'retentionDays' property to 90 (or higher) on the Microsoft.Sql/servers/auditingSettings resource, and confirm the backing storage account has matching or longer lifecycle retention so the policy is not silently overridden.
  3. Enforce it across the estate by assigning the built-in audit policy, looking the definition up by name rather than pasting a GUID: pid=$(az policy definition list --query "[?displayName=='SQL servers with auditing to storage account destination should be configured with 90 days retention or higher'].name" -o tsv); az policy assignment create --name sql-audit-retention --policy "$pid" --scope /subscriptions/<sub-id>. This definition is AuditIfNotExists, so it reports non-compliant servers but does not change retention for you.

Remediation script · bash

# Raise SQL audit retention to 90 days on a server that audits to a storage account.
# retentionDays only applies to the storage-account target; 0 would mean unlimited.
az sql server audit-policy update \
  --resource-group rg-data \
  --name sql-payments-prod \
  --state Enabled \
  --blob-storage-target-state Enabled \
  --storage-account stsqlauditprod \
  --retention-days 90

# Ratchet it shut: look the built-in policy up by its exact display name (never
# hardcode the GUID), then assign it so any server below 90 days is surfaced.
pid=$(az policy definition list \
  --query "[?displayName=='SQL servers with auditing to storage account destination should be configured with 90 days retention or higher'].name" \
  -o tsv)

az policy assignment create \
  --name audit-sql-retention-90 \
  --policy "$pid" \
  --scope "/subscriptions/00000000-0000-0000-0000-000000000000"

Full walkthrough (console steps, edge cases and verification) in the lesson Retain Azure audit and activity logs.

Is "Audit retention for SQL servers should be set to at least 90 days" a false positive?

A server that sends its audit logs only to Log Analytics or an Event Hub, where retention is governed by the workspace or hub rather than a 'retentionDays' value, can still surface here if storage auditing is also half-configured. The clean exception is a server with 'retentionDays' deliberately set to 0, which means audit blobs are never auto-deleted and are retained indefinitely: that satisfies the intent of the control even though a naive 'less than 90' check would flag it.