Repository navigation
Using the mssql‐odbc driver (Preview)
mssql-python loads one of two native ODBC providers:
| Provider | What it is | Status |
|---|---|---|
msodbcsql18 |
Microsoft ODBC Driver 18 for SQL Server, the established C++ driver | Default, unchanged |
mssql-odbc |
A new ODBC driver written in Rust | Preview, opt-in |
This article covers mssql-odbc 0.3.0, the version currently used by
mssql-python, and what differs from msodbcsql18.
Note:
mssql-odbcis under active development and validation. It's not yet a complete replacement for Microsoft ODBC Driver 18. Keepmsodbcsql18as your production default for now. The development team plans to close the preview gaps in upcoming releases, except for intentional exclusions explicitly identified in this article.
The driver ships inside the mssql-python-rs package as prebuilt wheels for
CPython 3.10 and later:
| Platform | Architectures |
|---|---|
| Windows | x64; ARM64 on CPython 3.11+ |
| macOS | universal2 (x86_64 + arm64), macOS 15 or later |
| Linux (glibc) | x86_64, aarch64 — manylinux_2_28 and manylinux_2_34
|
| Linux (musl) | x86_64, aarch64 — musllinux_1_2
|
The mssql-python package depends on mssql-python-rs, so a normal installation
brings the Rust driver with it:
pip install mssql-pythonIf you install with --no-deps or from a private index, install
mssql-python-rs explicitly as well.
Select the provider before the first connection, either with an environment variable:
PowerShell:
$env:MSSQL_PYTHON_NATIVE_PROVIDER = "mssql-odbc"Bash or Zsh:
export MSSQL_PYTHON_NATIVE_PROVIDER=mssql-odbcor from Python:
import mssql_python
mssql_python.native_provider = "mssql-odbc"Connect by using your application's existing connection string. Keep certificate validation enabled (Encrypt=yes;TrustServerCertificate=no). For authentication and certificate setup, see Connecting Application to SQL Database and Connection.
connection = mssql_python.connect(connection_string)The driver applies these rules when selecting the provider:
- The
MSSQL_PYTHON_NATIVE_PROVIDERenvironment variable takes precedence overnative_provider. A conflicting attribute assignment emitsRuntimeWarning. - Selection becomes fixed after connection-string validation and immediately before the native connection is constructed. A subsequent connection failure doesn't clear the selection. An earlier connection-string parsing error or missing provider package doesn't fix the selection. After selection is fixed, changing
native_providerto a different provider emitsRuntimeWarningand has no effect. Restart the process to switch providers. - An unrecognized provider name raises
ValueError; the driver doesn't fall back to the default provider. An unknown name assigned tonative_providerraises immediately. An unknown name in the environment variable raises when you attempt to connect. - Set
native_providertoNoneto clear the attribute selection before it becomes fixed. The environment variable still takes precedence.
Call mssql_python.get_native_provider_info() to inspect the selected provider, selection source, and whether selection is fixed. Before connecting, this reports the selection, not proof that the native driver has loaded successfully.
To go back, set the variable to msodbcsql18, or unset it and remove any
native_provider assignment from your code (or set it to "msodbcsql18").
Then restart the process.
The mssql-odbc driver implements every ODBC function that mssql-python calls, so most
applications can switch providers without code changes. Check
Known issues for the remaining differences.
| Area | Notes |
|---|---|
| Connection lifecycle | Connect, close(), with blocks, login timeout, diagnostics, and changing the current database. Connection-string settings include ApplicationIntent, MultiSubnetFailover, IpAddressPreference, PacketSize, KeepAlive, and ConnectRetryCount / ConnectRetryInterval (idle connection resiliency). |
| Authentication | SQL authentication (UID / PWD); Windows authentication (Trusted_Connection=Yes, using SSPI on Windows or Kerberos on Linux and macOS); and Microsoft Entra interactive, device code, service principal, managed identity, default credential, and access token. Entra integrated and password authentication aren't supported; see Known issues. |
| TLS |
Encrypt, TrustServerCertificate, HostnameInCertificate, and ServerCertificate. |
| Query execution | Direct and prepared execution, prepared-plan reuse, qmark parameters, and the pyformat conversion mssql-python performs. |
| ODBC escape syntax | Function, date/time, outer-join, GUID, LIKE ... {escape ...}, interval, and {encrypt ...} escape forms. |
| Stored procedures | Call them with T-SQL or positional {call ...} syntax through execute(), read result sets, and advance with nextset(). |
| Input parameters | Scalar parameters, SQL NULL, setinputsizes(), and mixed regular/streamed parameters. |
| Large parameters | Large text and binary parameters stream to the server on the ordinary binding path; XML and UDT parameter limitations are listed below. |
executemany() |
Batched with ODBC parameter arrays. Rows containing streamed values fall back to row-by-row execution. |
| Row fetching |
fetchone(), fetchmany(), fetchall(), iteration, fetchval(), typed conversion, and large text/binary streaming. |
| Arrow fetching |
arrow_batch(), arrow(), and arrow_reader(). Requires pyarrow. |
| Multiple result sets |
nextset(), including results produced by parameter arrays. |
| Transactions | Autocommit, commit, rollback, the automatic commit (or rollback, if an error escaped) that happens when a with connect(...) block ends, and the read-uncommitted, read-committed, repeatable-read, serializable, and snapshot isolation levels. |
| Query timeout | Set Connection.timeout (in seconds) to bound statements run by that connection's cursors; expiry raises OperationalError. 0 means no timeout. This setting is separate from the login timeout passed as connect(timeout=...). |
| Connection pooling | The built-in mssql-python pool, including connection reset on checkout and separate pools per Microsoft Entra identity. |
| Metadata APIs |
tables(), columns(), primaryKeys(), foreignKeys(), statistics(), rowIdColumns(), rowVerColumns(), procedures(), and getTypeInfo(). |
| Encoding and converters | Default wide-character encoding and output converters. Custom narrow-character decoding and non-Unicode parameter conversion have limitations listed in Known issues. |
You can read all SQL Server data types, and the driver supports every parameter
type that mssql-python binds. The driver returns xml, json, and vector
values as str (vector as a JSON array), and CLR types such as geometry,
geography, and hierarchyid as bytes. For other Python mappings, see
Data Type Conversion.
For type-specific limitations, see Known issues.
Check these differences before switching a workload from msodbcsql18.
| Issue | Details | Workaround |
|---|---|---|
| Microsoft Entra integrated authentication |
Authentication=ActiveDirectoryIntegrated isn't supported. Windows authentication (Trusted_Connection=Yes) is unaffected. |
Use another Microsoft Entra method, or keep msodbcsql18. |
| Microsoft Entra password authentication |
Authentication=ActiveDirectoryPassword isn't supported, and support isn't planned because this method can't satisfy MFA. SQL authentication (UID / PWD) is unaffected. |
Use another Microsoft Entra method, such as a service principal, managed identity, or access token. |
attrs_before settings |
Authentication, application intent, and multi-subnet failover can't be set as numeric attributes. Statement attributes other than query timeout are rejected. | Use the equivalent connection-string keywords. |
| Connection-operation timeout |
set_attr(SQL_ATTR_CONNECTION_TIMEOUT, ...) accepts and stores the value, but it doesn't enforce a timeout in 0.3.0. |
Use connect(timeout=...) for login and Connection.timeout for statements; neither is a general connection-operation deadline. |
| Multi-address hosts |
msodbcsql18 enables Transparent Network IP Resolution (TNIR) by default; mssql-odbc doesn't support it. mssql-python rejects the TransparentNetworkIPResolution connection-string keyword with either provider. Without MultiSubnetFailover=Yes, addresses are tried one at a time, so an unreachable address can delay the connection. Server-assisted DNS caching and enhanced routing aren't negotiated. |
Set MultiSubnetFailover=Yes for availability group listeners and other multi-address hosts. |
| Transient DNS failures | If a DNS lookup fails, the driver doesn't fall back to the last successful address. (#457) | Retry the connection. |
| Data classification | Sensitivity classification metadata isn't available, and SQL_COPT_SS_DATACLASSIFICATION_VERSION (1400) isn't supported. |
Query sys.sensitivity_classifications. |
| Multithreading | Multithreaded use hasn't been validated. | Keep msodbcsql18 for multithreaded workloads. |
fork() after connecting |
On Linux, a process forked after the parent connects can hang when it uses the driver, even with a new connection. With pooling enabled, the parent can hang too. (#566) | Use the spawn start method and connect inside each worker. |
| Canceling a running statement | A running query or fetch can't be interrupted. For example, closing an arrow_reader() doesn't stop a read in progress on another thread. |
Use Connection.timeout to limit long-running statements. |
| Unread results | Closing a cursor or running another statement reads and discards remaining results instead of canceling them, which can be slow. Closing a cursor that used a prepared statement ignores Connection.timeout and can hang if the server stops responding. (#546) |
Fetch only the rows you need, for example with TOP. |
Large xml and UDT parameters |
Values bound as SQL_SS_XML or SQL_SS_UDT through setinputsizes() are buffered in memory instead of streamed. |
Bind xml values as ordinary strings. |
Empty image values |
An empty, non-NULL SQL Server image value is returned as None instead of b"". |
Read CAST(image_column AS varbinary(max)), or use msodbcsql18 when the empty/NULL distinction matters. |
| Non-Unicode string parameters | Strings bound as char / varchar through setinputsizes() can be encoded incorrectly for code page 437, code page 850, and UTF-8 collations. |
Use the default string binding. |
| Legacy code-page decoding on Windows | With setdecoding(SQL_CHAR, encoding="cp1252") or another legacy code page, text can be decoded incorrectly or returned as bytes, because the driver returns char / varchar data as UTF-8. |
Use the default: conn.setdecoding(mssql_python.SQL_CHAR). |
Connection.getinfo() |
SQL_USER_NAME returns the connection-string UID, not the database user. It's empty when no UID reaches the driver. Some capability values and packet-size-based limits differ from msodbcsql18. |
Use SELECT USER_NAME() for the database user. |
| Out-of-memory failures | Some driver allocation failures end the Python process instead of raising MemoryError. (#484) |
Limit the size of values you send and fetch. |
| Large-value read performance | In one benchmark, chunked reads of varchar(max) / nvarchar(max) data were slightly slower than with msodbcsql18. (#473) |
Benchmark your workload. |
This list isn't exhaustive.
If you encounter a bug, select msodbcsql18, restart the process, and check whether
the behavior still occurs. Also remove any conflicting Python-side provider
assignment. The comparison helps isolate the problem; it doesn't by itself
prove its cause. Include the output of
mssql_python.get_native_provider_info(), your platform, and the failing SQL or
error message:
- Rust driver issues: https://github.com/microsoft/mssql-rs/issues
-
mssql-pythonissues: https://github.com/microsoft/mssql-python/issues
For Rust-driver diagnostics, set these variables before starting Python and
reproduce the problem with mssql-odbc selected. For example, in PowerShell:
$env:MSSQL_TDS_TRACE = "true"
$env:MSSQL_TDS_TRACE_LEVEL = "warn,mssqlodbc=debug"
$env:MSSQL_TDS_TRACE_DIR = "./traces"MSSQL_TDS_TRACE enables tracing, MSSQL_TDS_TRACE_LEVEL selects the log
filter, and MSSQL_TDS_TRACE_DIR writes per-process files instead of stderr.
Restart Python after changing these settings. Traces can contain SQL text and
parameter values. Review and redact sensitive data before sharing relevant
excerpts, and disable tracing after diagnosis.