Rediger

Microsoft Drivers for PHP for SQL Server

Download PHP driver

The Microsoft Drivers for PHP for SQL Server are PHP extensions that you can use to read and write data in the Microsoft SQL Database Engine from PHP scripts. The two extensions use the same Microsoft ODBC Driver for SQL Server, but they offer different PHP APIs and driver-specific options:

  • SQLSRV exposes a procedural API (sqlsrv_* functions) tailored to SQL Server features.
  • PDO_SQLSRV implements the PHP Data Objects (PDO) interface. You can keep the PDO calls in existing database code, but review its queries and driver-specific settings before switching databases.

Both drivers connect to Azure SQL Database, SQL database in Microsoft Fabric, Azure SQL Managed Instance, and all supported versions and editions of SQL Server, including Express editions. Both drivers accept PHP streams as input parameters. SQLSRV supports retrieving large binary and character values as streams. Don't assume PDO_SQLSRV has the same output-streaming behavior.

Choose your starting point

Production baseline for Azure SQL

This PDO_SQLSRV example reads the server and database from environment variables and connects with a managed identity. It builds a data source name (DSN) and enables Transport Layer Security (TLS) with certificate validation. Read these values from trusted application configuration, not web request parameters. Run the program on a host with a managed-identity endpoint after granting the identity access to the database.

The helper functions make up to three attempts to connect or run the read-only query when a listed error occurs. They wait longer between attempts, a retry pattern called exponential backoff. If a query error requires a new connection, the query helper throws the exception for the calling code to handle.

Use a supported PHP version, the PDO_SQLSRV extension, and Microsoft ODBC Driver 18 for SQL Server. For supported authentication values, see Connect using Microsoft Entra authentication. Don't reuse the query helper for writes or multistatement transactions without designing an application-specific retry policy: an error doesn't always tell you whether a write committed.

<?php
declare(strict_types=1);

// Transient errors that require a fresh connection to recover. SQLSTATE values
// starting with '08' cover ODBC connection-established and connection-broken
// states (for example, 08001, 08S01).
const CONNECT_RETRY_SQLSTATE_PREFIX = '08';

// SQL Server error codes that are transient regardless of when they surface:
// 1205 (deadlock victim), 1222 (lock request timeout), and the Azure SQL
// throttling, mid-query failover, and "database not currently available"
// codes that arrive with SQLSTATE HY000.
const TRANSIENT_SERVER_ERROR_CODES = [1205, 1222, 40501, 40613, 40197, 10928, 10929, 49918];

// This read helper retries only the listed errors on the same connection.
// Other errors propagate; the caller must decide whether to reconnect.
const RETRYABLE_READ_ERROR_CODES = [1205, 1222, 40501, 10928, 10929];

/**
 * Open a connection, retrying transient failures with exponential backoff.
 */
function connectWithRetry(string $dsn, array $options, int $maxAttempts = 3): PDO
{
    for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
        try {
            $pdo = new PDO($dsn, null, null, $options);
            error_log(sprintf('connected on attempt %d/%d', $attempt, $maxAttempts));
            return $pdo;
        } catch (PDOException $e) {
            $sqlstate = (string) $e->getCode();
            $driverCode = isset($e->errorInfo[1]) ? (int) $e->errorInfo[1] : 0;
            $isTransient = str_starts_with($sqlstate, CONNECT_RETRY_SQLSTATE_PREFIX)
                || in_array($driverCode, TRANSIENT_SERVER_ERROR_CODES, true);
            if (!$isTransient || $attempt === $maxAttempts) {
                error_log(sprintf('connect failed on attempt %d/%d: %s', $attempt, $maxAttempts, $e->getMessage()));
                throw $e;
            }
            $delay = 2 ** ($attempt - 1);
            error_log(sprintf('connect attempt %d hit transient %s/%d; retrying in %d seconds', $attempt, $sqlstate, $driverCode, $delay));
            sleep($delay);
        }
    }
    throw new RuntimeException('connectWithRetry exhausted retries');
}

/**
 * Retry the standalone read-only query for errors that allow connection reuse.
 */
function queryWithRetry(PDO $pdo, string $sql, array $params = [], int $maxAttempts = 3): PDOStatement
{
    for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
        try {
            $stmt = $pdo->prepare($sql);
            $stmt->execute($params);
            return $stmt;
        } catch (PDOException $e) {
            $driverCode = isset($e->errorInfo[1]) ? (int) $e->errorInfo[1] : 0;
            $isTransient = in_array($driverCode, RETRYABLE_READ_ERROR_CODES, true);
            if (!$isTransient || $attempt === $maxAttempts) {
                error_log(sprintf('query failed on attempt %d/%d: %s', $attempt, $maxAttempts, $e->getMessage()));
                throw $e;
            }
            $delay = 2 ** ($attempt - 1);
            error_log(sprintf('query attempt %d hit transient code %d; retrying in %d seconds', $attempt, $driverCode, $delay));
            sleep($delay);
        }
    }
    throw new RuntimeException('queryWithRetry exhausted retries');
}

// Load endpoint details from application configuration. In Azure App Service,
// these can come from app settings or Key Vault-backed settings.
$server = getenv('SQL_SERVER') ?: null;
$database = getenv('SQL_DATABASE') ?: null;

if ($server === null || $database === null) {
    throw new RuntimeException('Set SQL_SERVER and SQL_DATABASE in your application configuration.');
}
$databaseValue = '{' . str_replace('}', '}}', $database) . '}';

$dsn = sprintf(
    'sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=%s;Database=%s;'
    . 'Encrypt=true;TrustServerCertificate=false;'
    . 'LoginTimeout=90;Authentication=ActiveDirectoryMsi;'
    . 'ConnectRetryCount=5;ConnectRetryInterval=15;'
    . 'MultiSubnetFailover=true;',
    $server,
    $databaseValue
);

$options = [
    PDO::ATTR_ERRMODE               => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE    => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES      => false,
    PDO::SQLSRV_ATTR_QUERY_TIMEOUT  => 30,
];

$pdo = connectWithRetry($dsn, $options);
$stmt = queryWithRetry($pdo, 'SELECT name FROM sys.databases WHERE database_id > ? ORDER BY name', [1]);
foreach ($stmt as $row) {
    echo $row['name'], PHP_EOL;
}

Use these settings for Azure SQL Database failover groups and Azure SQL Managed Instance.

  • Driver={ODBC Driver 18 for SQL Server} selects ODBC Driver 18 explicitly rather than relying on driver discovery. Install it before running the example.

  • Set SQL_DATABASE to the actual database name. The program doubles closing braces and encloses the name in braces before placing it in the DSN. Escaping keeps special characters in the name from changing how the driver reads connection settings.

  • ConnectRetryCount and ConnectRetryInterval control ODBC idle connection resiliency. The statement's query timeout bounds recovery during execution. With the sample's 30-second query timeout, ODBC might stop before exhausting all five reconnect attempts. LoginTimeout=90 controls connection establishment, not that recovery budget. The application-level helper retries selected server errors; it doesn't retry a query timeout or replay partially fetched results.

  • Enable driver logging alongside the program's error_log() calls. For PDO_SQLSRV, set pdo_sqlsrv.log_severity in php.ini or with ini_set() at runtime. For SQLSRV, configure LogSeverity and LogSubsystems with sqlsrv_configure(). For more information, see Logging activity.

    ; php.ini - enable PDO_SQLSRV driver diagnostics alongside the application-level
    ; error_log() calls in the sample. Use 1 (errors) in production; -1 (all) is
    ; useful during triage but very chatty.
    [pdo_sqlsrv]
    pdo_sqlsrv.log_severity = 1
    
  • For a user-assigned managed identity, pass the identity's ID as PDO's $username argument (new PDO($dsn, $identityId, null, $options)). Use the identity's client ID on Azure App Service or Azure Container Instance; otherwise, use its object ID. The PHP drivers inherit this behavior from the underlying Microsoft ODBC Driver for SQL Server; for more information, see Using Microsoft Entra ID with the ODBC Driver. Use the PDO constructor's username argument rather than embedding the identity in the DSN. Passing null as the user (as the sample does) selects the system-assigned managed identity of the Azure host. For SQLSRV (procedural), pass UID in the connection options array.

  • Set MultiSubnetFailover=true when you connect to a failover-group listener, availability group listener, or failover cluster instance endpoint. Setting it improves connection performance for both single-subnet and multi-subnet availability group listeners. For more information, see Support for High Availability, disaster recovery.

  • For read scale-out or a readable secondary, add ApplicationIntent=ReadOnly to the DSN.

  • Use the endpoint supplied by your SQL service, including its cloud-specific domain. Investigate certificate-name mismatches rather than disabling certificate validation. Use HostNameInCertificate only when you know the expected certificate name for that endpoint.

  • ODBC acquires tokens for managed identity and service principal authentication. With AccessToken, your application acquires the token and passes it to the driver; ODBC doesn't acquire it for you. For more information, see Using Microsoft Entra ID with the ODBC Driver.

  • Keep connection information outside your code. Store it in your application's configuration system, and use Azure Key Vault for secrets.

  • With SQLSRV, set connection options in the array passed to sqlsrv_connect(). Check for a false return and inspect sqlsrv_errors() before deciding whether to retry. Set statement timeouts separately with QueryTimeout. Idle connection resiliency demonstrates ODBC reconnection, not an application-level retry loop.

  • The retry helpers read $e->errorInfo[1] guarded by isset(). PDOException::$errorInfo is declared as ?array and defaults to null, so the defensive check falls back to a driver code of 0 and lets the SQLSTATE 08 prefix decide whether to retry.

For more information about each part of this configuration, see:

For the catalog of Azure SQL transient errors, see Troubleshoot transient connection errors.

Key features

  • Two PHP APIs: SQLSRV provides procedural functions. PDO_SQLSRV implements PDO. Install either extension or both.
  • Wide platform support: Runs on Windows, Linux, and macOS with supported PHP versions.
  • Encrypted connections: TLS-encrypted connections via Encrypt=true, with server certificate validation controlled by TrustServerCertificate.
  • Microsoft Entra ID authentication: Managed identity, service principal, and externally acquired access tokens through the underlying Microsoft ODBC Driver for SQL Server. Managed identity is passwordless; ActiveDirectoryServicePrincipal uses a client secret.
  • Always Encrypted: Encrypt sensitive columns on the client, with secure enclaves for supported operations on encrypted data.
  • Connection resiliency: Built-in idle connection retries with ConnectRetryCount and ConnectRetryInterval.
  • PHP streams: Send large binary and character values from stream parameters with either API. Use SQLSRV for streamed retrieval.
  • Rich SQL Server data type support: datetimeoffset, table-valued parameters, nvarchar, and Unicode with PDO::SQLSRV_ENCODING_UTF8.

Get started

Article Description
System requirements Supported PHP, operating system, and SQL Server versions.
Support matrix Detailed compatibility matrix for PHP driver releases.
Download the Microsoft Drivers for PHP for SQL Server Download links and release artifacts.
Installation tutorial for Linux and macOS Install the driver and its ODBC prerequisites on Linux and macOS.
Loading the drivers Enable the extensions in php.ini.
Quickstart: Connect and query with the Microsoft Drivers for PHP Verify the extensions, configure a connection, and run the same parameterized query with SQLSRV or PDO_SQLSRV.
Overview of the PHP SQL driver What's in the package, and when to choose SQLSRV or PDO_SQLSRV.

Configure and connect

Article Description
Connecting to the server Open a connection to a SQL Server instance from PHP.
Connection options Full reference for connection keywords, defaults, and how to set them.
Connecting to Microsoft Azure SQL Database Connect a PHP application to Azure SQL Database.
Connect on a specified port Target a nondefault TCP port.
Connection pooling Reuse ODBC connections across PHP requests.
Disable Multiple Active Result Sets (MARS) Turn off MARS for compatibility.
Support for LocalDB Connect to a SQL Server LocalDB instance.
Support for High Availability, disaster recovery Availability group listeners and multi-subnet failover.
Idle connection resiliency Automatic reconnect for broken idle connections.

Authenticate

Article Description
Connect using Microsoft Entra authentication Managed identity, service principal, access token, and password flows.
Connect using SQL Server authentication Use a SQL login with a username and password.
Connect using Windows authentication Use integrated authentication on Windows or Kerberos on Linux and macOS.

Secure

Article Description
Security considerations Threat model and defense-in-depth guidance for PHP applications.
Always Encrypted with the PHP drivers Configure client-side encryption for sensitive columns.
Always Encrypted with secure enclaves Enable rich operations on encrypted columns with secure enclaves.

Retrieve and update data

Article Description
Programming guide Find programming tasks for both drivers.
Comparing execution functions Choose the right execution function for your workload.
Direct and prepared statement execution (PDO_SQLSRV) When to use direct execution versus prepared statements.
Retrieving data Fetch rows, columns, and streaming values.
Updating data Insert, update, and delete rows.
Perform parameterized queries Bind parameters to protect against SQL injection.
Send data as a stream Stream large binary and character values into SQL Server.
Perform transactions Commit or roll back a group of statements together.
Use table-valued parameters Pass a TABLE parameter to a stored procedure.
Specify a cursor type and select rows Choose forward-only, static, dynamic, or keyset cursors.

Data types

Article Description
Converting data types How the driver maps PHP types to SQL Server types.
Default SQL Server data types Default SQL Server type for each PHP value.
Default PHP data types Default PHP type for each SQL Server column type.
Specify SQL Server data types (SQLSRV) Override the SQL Server type when binding parameters.
Specify PHP data types Override the PHP type when fetching.
Send and retrieve UTF-8 data Set SQLSRV's CharacterSet option or PDO_SQLSRV's PDO::SQLSRV_ATTR_ENCODING attribute.
Send and retrieve ASCII data on Linux and macOS Handle ASCII round-trips on non-Windows hosts.
Format decimals and money (SQLSRV) Format decimal and money columns with the SQLSRV driver.
Format decimals and money (PDO_SQLSRV) Format decimal and money columns with the PDO_SQLSRV driver.
Non-system locale settings Localized decimal separators and other locale considerations.

Errors and diagnostics

Article Description
Handling errors and warnings Error and warning handling with both drivers.
Configure error and warning handling (SQLSRV) Tune how the SQLSRV driver reports errors and warnings.
Handle errors and warnings (SQLSRV) Inspect errors returned by SQLSRV functions.
Logging activity Enable driver logging for diagnostic capture.

Deploy and operate

Article Description
Performance tuning Connection management, batching, prepared statements, cursors, memory, and server-side monitoring.
Troubleshooting Diagnose common install, connection, query, data type, transaction, and container problems.

Reference content

Article Description
SQLSRV driver API reference All sqlsrv_* functions, parameters, and return values.
PDO_SQLSRV driver reference PDO and PDOStatement methods supported by the PDO_SQLSRV driver.
Constants Constants exposed by the drivers, including type and encoding constants.
Article Description
Release notes Per-version history with new features, bug fixes, platform support changes, and download links.
About code samples in the documentation Conventions used by the code samples in this section.
Code samples for the PHP SQL driver End-to-end example applications for SQLSRV and PDO_SQLSRV.
Support resources Community and support channels.

Request a feature

To request a feature, open an issue in the Microsoft Drivers for PHP for SQL Server GitHub repository.