You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Microsoft Python Driver for SQL Server - mssql-python
description
mssql-python is Microsoft's Python driver for SQL Server, Azure SQL Database, Azure SQL Managed Instance, and SQL database in Microsoft Fabric.
author
dlevy-msft-sql
ms.author
dlevy
ms.reviewer
vanto, randolphwest
ms.date
07/13/2026
ms.service
sql
ms.subservice
connectivity
ms.topic
get-started
ms.custom
ignite-2025
ai-usage
ai-assisted
Microsoft Python Driver for SQL Server - mssql-python
mssql-python is Microsoft's Python driver for SQL Server, Azure SQL Database, Azure SQL Managed Instance, and SQL database in Microsoft Fabric. It uses Direct Database Connectivity (DDBC), so you can connect without installing an external driver manager. The driver supports Python 3.10 or later and complies with the Python Database API Specification 2.0 while adding Python-friendly improvements for day-to-day development.
Use this sample as a starting point for a production-oriented Azure SQL connection. It reads configuration from the environment, authenticates with managed identity, and enables Tabular Data Stream (TDS) 8.0 encryption. It also sets login and per-statement query timeouts, retries transient failures with exponential backoff (a fresh connection for connection errors, the same connection for query errors like deadlocks), logs outcomes, and relies on context managers to release resources.
The ConnectRetryCount and ConnectRetryInterval keywords in the connection string enable SQL Server idle connection resiliency: the driver transparently reconnects a dropped idle connection. That's distinct from the application-level retry in this sample, which retries a query that fails with a transient error such as a deadlock or query timeout. The two are complementary, so keep both.
importloggingimportosimporttimeimportmssql_pythonlogging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
logger=logging.getLogger("app")
# Transient errors that require a fresh connection to recover.CONNECT_RETRY_ERRORS=frozenset({
"Timeout expired",
"Connection timeout expired",
"Client unable to establish connection",
"Communication link failure",
"Connection failure during transaction",
})
# Transient errors that leave the connection usable, such as a deadlock victim# or a query timeout, so retry on the same connection.QUERY_RETRY_ERRORS=frozenset({
"Serialization failure",
"Timeout expired",
})
defconnect_with_retry(conn_str: str, max_attempts: int=3, login_timeout_s: int=5) ->mssql_python.Connection:
"""Open a connection, retrying transient failures with exponential backoff."""forattemptinrange(1, max_attempts+1):
try:
conn=mssql_python.connect(
conn_str,
attrs_before={mssql_python.SQL_ATTR_LOGIN_TIMEOUT: login_timeout_s},
)
logger.info("connected on attempt %d/%d", attempt, max_attempts)
returnconnexceptmssql_python.OperationalErrorasexc:
ifexc.driver_errornotinCONNECT_RETRY_ERRORSorattempt==max_attempts:
logger.error("connect failed on attempt %d/%d: %s", attempt, max_attempts, exc.driver_error)
raisedelay=2** (attempt-1) # 1s, 2s, 4slogger.warning(
"connect attempt %d/%d hit transient error %r; retrying in %ds",
attempt, max_attempts, exc.driver_error, delay,
)
time.sleep(delay)
defexecute_with_retry(
conn: mssql_python.Connection,
sql: str,
*params,
max_attempts: int=3,
query_timeout_s: int=10,
) ->mssql_python.Cursor:
"""Run sql on an open connection and return the ready-to-fetch cursor. Retries errors that leave the connection usable so callers don't wrap each query in its own function. Pass query values as parameters. Retry only idempotent statements; wrap writes in an explicit transaction. """forattemptinrange(1, max_attempts+1):
cursor=mssql_python.Cursor(conn, timeout=query_timeout_s)
try:
cursor.execute(sql, *params)
ifattempt>1:
logger.info("query succeeded on attempt %d/%d", attempt, max_attempts)
returncursorexceptmssql_python.OperationalErrorasexc:
cursor.close()
ifexc.driver_errornotinQUERY_RETRY_ERRORSorattempt==max_attempts:
logger.error("query failed on attempt %d/%d: %s", attempt, max_attempts, exc.driver_error)
raisedelay=2** (attempt-1) # 1s, 2s, 4slogger.warning(
"query attempt %d/%d hit transient error %r; retrying in %ds",
attempt, max_attempts, exc.driver_error, delay,
)
time.sleep(delay)
raiseRuntimeError("unreachable: the retry loop exits by return or raise")
defmain() ->None:
# Read configuration from the environment; never hard-code secrets.server=os.environ["SQL_SERVER"] # for example, myserver.database.windows.netdatabase=os.environ["SQL_DATABASE"] # for example, AdventureWorksclient_id=os.getenv("AZURE_CLIENT_ID") # set for a user-assigned managed identity# Authenticate with the workload's managed identity over TDS 8.0 encryption.# ConnectRetryCount/ConnectRetryInterval transparently reconnect a dropped# idle connection; they don't replay a failed query.conn_str= (
f"Server={server};"f"Database={database};""Authentication=ActiveDirectoryMsi;""Encrypt=strict;""ConnectRetryCount=3;""ConnectRetryInterval=10;"
)
ifclient_id:
conn_str+=f"UID={client_id};"query=""" SELECT TOP 10 p.BusinessEntityID, p.FirstName, p.LastName FROM Person.Person AS p ORDER BY p.BusinessEntityID; """try:
# Context managers close the cursor and connection automatically.withconnect_with_retry(conn_str) asconn:
withexecute_with_retry(conn, query) ascursor:
forbusiness_entity_id, first_name, last_nameincursor.fetchall():
print(f"{business_entity_id}\t{first_name}\t{last_name}")
exceptmssql_python.Error:
logger.exception("query failed")
raiseif__name__=="__main__":
main()
Apache Arrow integration: Zero-copy result sets for fast data interchange with pandas, Polars, and DuckDB.
Async patterns: Use the driver with asyncio-based applications and FastAPI through ThreadPoolExecutor workarounds. See Async patterns for integration patterns.