Azure Web App托管标识连接SQL Database数小时后随机登录失败
问题根因
这是托管标识连接Azure SQL的经典连接池令牌过期故障,和数据库权限配置无关。
托管标识从Azure实例元数据服务获取的、用于访问Azure SQL的Azure AD访问令牌默认有效期为60-90分钟。默认配置下Microsoft.Data.SqlClient会开启连接池复用连接,旧版本客户端存在逻辑缺陷:不会在复用连接时检查绑定到连接的令牌是否过期,也不会主动获取新令牌重建连接。刚重启应用时连接池为空,新建连接会获取全新的有效令牌,所以启动后一段时间内运行正常;等池内缓存的第一批连接绑定的令牌全部过期后,所有复用这些连接的请求都会触发SQL端的令牌校验失败,抛出你看到的登录错误。
排查方向
- 先核对连接字符串配置:必须显式指定认证模式为
Active Directory Managed Identity,不要用代码手动获取令牌再拼接连接的写法——这种写法客户端完全感知不到令牌有效期,必然会出现过期问题。正确的基础连接字符串格式如下:
Server=tcp:<你的数据库实例名>.database.windows.net,1433;Database=<你的业务库名>;Authentication=Active Directory Managed Identity;
如果使用用户分配托管标识,还要额外加User Id=<托管标识对应的客户端ID>参数,不过这类配置错误一般启动时就会报错,和你描述的运行数小时后失效的特征不符,排查优先级可以放后面。
- 核对依赖版本:虽然你提到已经升级适配版本,但要注意2.1.0以下版本的Microsoft.Data.SqlClient存在明确的连接池令牌刷新bug,完全不会自动处理复用时的令牌过期问题。如果是EF Core场景,要确认间接依赖的Microsoft.Data.SqlClient版本至少在2.1.4以上,稳妥起见直接升到3.1.x及以上的LTS版本。
- 核对连接池配置:ADO.NET连接池默认
ConnectionLifetime参数值为0,意思是进入池的连接永远不会被主动回收,除非被数据库服务端主动断开。这种配置下绑定了过期令牌的连接会一直留在池里被反复复用,持续触发报错。
修复方案
- 升级依赖:将Microsoft.Data.SqlClient升级到3.1.0以上的稳定LTS版本,EF Core同步升级到6.0以上的长期支持版本,新版本内置了托管标识令牌的自动刷新逻辑,会在连接复用时检查令牌有效期,过期前主动获取新令牌重建连接。
- 调整连接池参数:在连接字符串中添加以下配置,强制旧连接定期回收,作为版本升级后的兜底:
Connection Lifetime=120;Pooling=true;Max Pool Size=100;
这里Connection Lifetime=120表示连接返回连接池时,如果创建时间已经超过120秒就会被直接销毁,不会继续复用。这个值远小于令牌默认1小时的有效期,完全可以避免过期连接留存,对性能的影响可以忽略。
- 加瞬时错误重试:为数据库操作添加指数退避的重试逻辑,遇到令牌过期、网络闪断这类瞬时错误时,自动销毁失效连接、新建连接重试。EF Core可以直接启用内置的SQL Server执行重试策略,不需要手动实现重复逻辑。
验证方式
部署修复版本后,不需要等数小时复现,等应用连续运行1.5小时后手动触发各类数据库操作,如果没有登录报错就说明修复生效。也可以在日志中埋点记录连接创建时间,确认连接池中的连接按配置定期重建即可。
内容的提问来源于stack exchange,提问作者Nayden Van
相关产品推荐
相关产品推荐

