PHP连接Azure SQL数据库核心是PDO_SQLSRV驱动、环境变量获取连接字符串、ODBC重试与应用层指数退避。需装对扩展、启用TLS、禁用MARS、显式指定fetch模式,并确保域名含.database.windows.net后缀。

PHP 连接 Azure SQL 数据库,核心不是“能不能连”,而是“用什么驱动 + 怎么传凭据 + 怎么防断连”。PDO_SQLSRV 是当前推荐路径,尤其在 Azure App Service 等托管环境中。
必须装对扩展:pdo_sqlsrv 而不是 mysqlnd
Windows 下 PHP 自带 pdo_sqlsrv 和 sqlsrv 扩展(需启用);Linux/macOS 必须手动安装 Microsoft ODBC 驱动 + pdo_sqlsrv 扩展。漏掉任一环都会报 Class 'PDO' not found 或 Driver not found。
- 确认已加载:
php -m | grep -i sqlsrv(Linux/macOS)或查看phpinfo()输出中是否有PDO drivers包含sqlsrv - Linux 安装顺序不能错:先装
msodbcsql17(或msodbcsql18),再用pecl install pdo_sqlsrv,最后在php.ini加extension=pdo_sqlsrv.so - Azure App Service(Linux)默认不预装该扩展,需通过自定义启动脚本或使用“应用设置”中的
PHP_EXTENSIONS启用(值填pdo_sqlsrv)
连接字符串里不能硬编码密码,优先用 AZURE_SQL_CONNECTIONSTRING
Azure 服务连接器(如 App Service → SQL)会自动注入 AZURE_SQL_CONNECTIONSTRING 环境变量,格式为 Data Source=xxx.database.windows.net,1433;Initial Catalog=xxx;...。直接读它,比拼接字符串更安全、更兼容托管环境。
- 代码里用
getenv('AZURE_SQL_CONNECTIONSTRING')或$_ENV['AZURE_SQL_CONNECTIONSTRING']获取(确保variables_order包含E) - 若手动构造,必须显式指定端口(
,1433),否则 Linux 上可能因 DNS 解析延迟导致超时;TLS 必须开启(Encrypt=yes),且验证证书(TrustServerCertificate=no) - 避免用
UID/PWD显式传账号密码——App Service 不支持系统托管标识(MI)直连 PHP,所以 MI 认证目前不可用;只能走连接字符串里的密码或应用设置中的密钥
连接失败别裸奔重试:加 ConnectRetryCount 和指数退避
Azure SQL 的故障转移可能耗时 30–60 秒,单纯 new PDO(...) 失败就抛异常,会导致请求直接 500。ODBC 层的 ConnectRetryCount 和 ConnectRetryInterval 是第一道防线。
立即学习“PHP免费学习笔记(深入)”;
- 在 DSN 中加入:
;ConnectRetryCount=3;ConnectRetryInterval=10(最多重试 3 次,间隔 10 秒) - 但 ODBC 层重试只管“建连”,不管“查询失败”。查询级瞬态错误(如 40613、40197)需应用层捕获
PDOException并做有界指数退避(首次延 5s,二次 10s,三次 20s,上限 60s) - 不要在事务中间重试单条语句——要么整个事务重放,要么明确 rollback 后重建连接再重试
查不到数据?先关 MARS,再看 fetch_mode
默认启用 Multiple Active Result Sets(MARS)在某些 Azure SQL 版本或网络条件下会引发 SQLSTATE[HY000]: General error 或游标静默失效。而 PDO::FETCH_ASSOC 不是默认行为,容易误以为没结果。
- 连接选项中加
'MultipleActiveResultSets' => false - 执行
$stmt->fetchAll(PDO::FETCH_ASSOC)显式指定,别依赖全局setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, ...)(易被框架覆盖) - 调试时用
$stmt->columnCount()和$stmt->rowCount()确认是否真没数据,还是 fetch 方式不对
最常被忽略的是:Azure SQL 的连接字符串中 Data Source 域名必须带 .database.windows.net 后缀,少一个点或写成 .database.azure.com 就会解析失败;另外,App Service 应用设置里如果把连接字符串放在 SQLSERVER_CONNECTIONSTRING 这类自定义名下,却没在代码里读它,那等于没配。



















