Azure SQL Database credential expiration limits for least-privilege database access
0 reputation · 21 Apr 2024, 18:45 UTC
0 reputation · 21 Apr 2024, 18:45 UTC
Azure SQL Database supports least-privilege access by mapping Azure AD users or groups to contained database users and assigning built-in roles such as db_datareader or db_datawriter, avoiding server-level logins. Under current Azure AD integration, access tokens issued for this resource have a limited lifetime—commonly described as approximately one hour, though exact durations depend on current Azure AD policy—after which new connections fail until a fresh token is acquired. By contrast, SQL authentication logins in Azure SQL Database do not enforce password expiration or complexity policies, so those passwords remain valid until explicitly changed or the login is disabled.
This creates an unresolved boundary for applications that combine minimal standing privileges with long-running sessions or cached credentials. Client-side token caching may reuse an expired token, making it difficult to distinguish whether repeated authentication failures originate from the token lifetime itself or from cache invalidation behavior.
What are the documented limits for re-authenticating a contained database user when a connection or cached credential outlives the Azure AD token lifetime? How does Azure SQL Database handle token expiration for existing sessions versus new connection attempts? Is there a supported way to align SQL authentication password rotation with short-lived Azure AD tokens without introducing higher-privilege server logins?
32275 reputation · 21 Apr 2024, 19:02 UTC
Azure AD access tokens issued for Azure SQL Database (resource https://database.windows.net/) are short-lived—commonly around one hour under default policy, though the exact lifetime depends on current tenant and Conditional Access settings. When that token expires, existing open sessions generally remain usable until the client attempts to re-authenticate, such as when a pooled connection is checked out or a broken connection is re-established. New connection attempts made with an expired token fail until a fresh token is acquired. SQL authentication logins in Azure SQL Database do not enforce password expiration or complexity by default (CHECK_POLICY=OFF), so those passwords remain valid until manually changed or the login is disabled. There is no built-in server-side mechanism to auto-refresh Azure AD tokens for existing sessions, and no native feature that synchronizes SQL auth password rotation with Azure AD token lifetimes.
The intermittent failures you describe are most likely caused by two client-side behaviors rather than a server-side session kill. First, a cached Azure AD token may be reused past its expires_on value. Second, connection poolers may hold idle connections open beyond the token lifetime and present them to the application without re-validating the credential. The confirmed server-side behavior is that Azure SQL accepts the token at connection establishment and does not proactively terminate an already-established session when the token expires; the failure surfaces on the next authentication attempt.
SELECT auth_scheme FROM sys.dm_exec_sessions WHERE session_id = @@SPID; on the active session.SELECT is_policy_checked, is_expiration_checked FROM sys.sql_logins WHERE name = 'your_login'; Both should be 0 when policy checks are off.Because token lifetimes are governed by tenant policy, verify the actual expires_on value for a token acquired against https://database.windows.net/ in your environment before sizing pool lifetimes. The commands above are read-only and safe to run. Enabling CHECK_POLICY=ON on a SQL login imposes Windows-style password policy but does not align expiration with Azure AD tokens and may introduce conflicts, so external rotation via a secret store remains the supported path.
One diagnostic detail that would change the recommendation: which client driver and connection pool implementation are you using (for example, Microsoft.Data.SqlClient with ADO.NET pooling, ODBC, or a language-specific pool)? The fix differs: some pools expose token-refresh callbacks, while others require manual lifetime tuning or custom retry logic.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.