mrkeyoor.com_
Sun 20 Sept 07:01 UTC
PyPIDataupdated 20 Sept 2026

databricks-sql-connector review

Databricks SQL Connector is the vendor's Python DB API 2.0 driver for SQL warehouses and compatible clusters. It talks to Databricks over HTTPS through a Thrift client, so hosts do not need an ODBC or JDBC driver. Cursors execute parameterized SQL, expose catalog metadata, cancel statements, move files through staging commands, and can return Arrow tables when the optional PyArrow extra is installed. Release 4.4.0 drops Python 3.9, reports affected-row counts for DML on the Thrift backend, and stops requiring a local staging path for remote REMOVE operations. Our clean install imported quickly and had no audit findings, though its resolved environment still occupied 114 MB.

Verdict

Use this connector for direct Python access to Databricks SQL, especially when Arrow results or OAuth matter. Pick databricks-sqlalchemy for ORM code, and use file staging plus COPY INTO instead of treating executemany as a bulk loader.

We installed it

Lab card: what happened when we installed databricks-sql-connectorScreenshot of databricks-sql-connector documentation
Install✓ · 0.9s17 packages on disk · 114 MB
Importimport databricks in 0.09s · pure Python · py.typed · requires Python >=3.10,<4.0
Known vulns0(pip-audit)

Answers from our run

Does databricks-sql-connector install cleanly?

Yes. In a fresh container with an empty cache, pip install databricks-sql-connector finished in 0.9s, leaving 17 packages and 114 MB on disk. pip-audit reported no known vulnerabilities.

What does databricks-sql-connector need to run?

Python >=3.10,<4.0, and nothing compiled: it is pure Python. In our run import databricks succeeded in 0.09s, and the package ships py.typed for type checkers.

databricks-sql-connector or databricks-sdk: which should you use?

databricks-sdk: Use it for jobs, clusters, workspace objects, and other REST APIs when running SQL is only a small part of the task. Use this connector for direct Python access to Databricks SQL, especially when Arrow results or OAuth matter.

When should you not use databricks-sql-connector?

You need a lean client for one small query. Our installation produced 17 packages and used 114 MB, before your application code or cached results.

API stability4/5PEP 249 keeps the connection, cursor, execute, fetch, commit, and rollback surface familiar. Server-side native parameters have been the default since 3.0.0, with compatibility for older pyformat markers. Major releases still require attention: 4.0.0 removed the SQLAlchemy dialect into another distribution, while 4.4.0 raised the Python floor to 3.10 and changed DML rowcount behavior on the Thrift backend.
Docs3/5Databricks publishes an official connector guide, connection-parameter reference, transaction guide, proxy notes, and repository examples for OAuth, cancellation, staging, and parameter binding. The material explains both Thrift and kernel paths. There is still a version trap: the current README requirement line says Python 3.9 while the 4.4.0 package metadata and release notes require Python 3.10, so packaging metadata must win when the two disagree.
Maintenance5/5Databricks maintains the repository directly, and its latest push was 2026-08-23. Release 4.4.0 shipped on 2026-07-22 with a supported-Python update, dependency cleanup, corrected staging permissions, and proper affected-row counts for DML. The repository reports 175 open issues and pull requests, which deserves triage attention, but the release cadence and vendor ownership give users a clear maintenance path.
Ecosystem3/5The connector fits the wider Databricks stack through OAuth, Unity Catalog metadata, SQL warehouses, interactive clusters, Arrow results, staging operations, and the separate SQLAlchemy dialect. DB API 2.0 reduces adaptation work for basic query code. Vendor-specific connection details, authentication, staging syntax, and warehouse behavior remain, so moving the same application to another database still requires a dedicated integration layer.

Use it if

  • Your Python service must query a Databricks SQL warehouse without installing a system ODBC or JDBC driver.
  • Existing code expects PEP 249 connections, cursors, bound parameters, row metadata, commit, and rollback.
  • Large query results should arrive as Arrow tables for transfer into pandas, Polars, or another Arrow-aware consumer.
  • The same client needs OAuth credentials, Unity Catalog metadata calls, query cancellation, or volume staging commands.
Skip it if

Setup reality

We installed databricks-sql-connector 4.4.0 in a clean Python 3.12 Bookworm container. It completed in 0.9 seconds, resolved 17 packages, and used 114 MB on disk. The package declares 16 direct dependencies, requires Python 3.10 through 3.x, is pure Python, includes py.typed, and carries Apache-2.0 licensing. import databricks worked in 0.09 seconds. pip-audit found 0 known vulnerabilities in that resolved environment. Arrow fetching and the Rust kernel backend use optional extras that can change what gets installed.

A connection needs a bare server_hostname, an http_path copied from the warehouse or cluster connection details, and credentials. Supplying a full https:// workspace URL where the hostname belongs is a common configuration error. Personal access tokens go in access_token. OAuth user-to-machine may open a browser, which rules it out for unattended jobs. Machine-to-machine examples use a credentials provider and the separately installed Databricks SDK; the service principal also needs workspace assignment and permission on the target compute and data.

PyArrow is required for fetchall_arrow() and fetchmany_arrow(). The [kernel] extra installs the native Rust client core and PyArrow, then use_kernel=True selects it. Version 4.4.0 no longer supports Python 3.9. Autocommit starts enabled, so transaction code must disable it before relying on rollback. execute_async() is a pollable connector API rather than an asyncio coroutine. For bulk loading, avoid executemany() at scale because parameter sets run separately; upload files to a volume and issue COPY INTO instead.

Patterns

Open a token-authenticated connection connect-and-query

import os
from databricks import sql

with sql.connect(
    server_hostname=os.getenv("DATABRICKS_SERVER_HOSTNAME"),
    http_path=os.getenv("DATABRICKS_HTTP_PATH"),
    access_token=os.getenv("DATABRICKS_TOKEN"),
) as connection:
    with connection.cursor() as cursor:
        cursor.execute("SELECT * FROM range(10)")
        for row in cursor.fetchall():
            print(row)

Pass only the host name to server_hostname and copy http_path from Compute connection details. Context managers close the cursor and the remote session even when execution raises.

Bind named query values named-parameters

with connection.cursor() as cursor:
    cursor.execute(
        "SELECT :name AS name, :age AS age, :active AS active",
        {"name": "Jane", "age": 30, "active": True},
    )
    print(cursor.fetchone())

Native server-side binding is the default. Keep values outside the SQL string; inline parameter mode performs client-side substitution and reintroduces injection risk.

Read one row several ways read-rows-as-dicts

cursor.execute("SELECT id, name FROM main.default.users LIMIT 5")
rows = cursor.fetchall()

print(rows[0][0])          # positional, Row subclasses tuple
print(rows[0].name)        # attribute access
print(rows[0].asDict())    # {"id": 1, "name": "Jane"}

Connector rows behave like tuples and also expose fields by name. Use cursor.description when downstream code needs the server-reported column metadata.

Receive an Arrow table or chunks fetch-arrow-table

cursor.execute("SELECT * FROM samples.nyctaxi.trips LIMIT 100000")
table = cursor.fetchall_arrow()   # pyarrow.Table
df = table.to_pandas()

# or stream it in chunks
cursor.execute("SELECT * FROM big_table")
while (batch := cursor.fetchmany_arrow(50_000)).num_rows:
    process(batch)

Install the pyarrow extra before using either method. Chunked fetching bounds client memory when a complete result table would be too large.

Build a multi-row insert bulk-insert

with connection.cursor() as cursor:
    cursor.execute("CREATE TABLE IF NOT EXISTS squares (x int, x_squared int)")

    squares = [(i, i * i) for i in range(1000)]
    values = ",".join(f"({x}, {y})" for x, y in squares)
    cursor.execute(f"INSERT INTO squares VALUES {values}")

This example controls its own integers, so interpolation is safe here. For real bulk ingestion, stage a file and run COPY INTO; executemany submits parameter sets separately.

Poll an asynchronously submitted statement async-execute

import time

with connection.cursor() as cursor:
    cursor.execute_async("SELECT COUNT(*) FROM huge_fact_table")

    while cursor.is_query_pending():
        time.sleep(5)

    cursor.get_async_execution_result()
    print(cursor.fetchall())

execute_async starts a server query and returns control, but it does not produce an awaitable. Poll at a sensible interval, then call get_async_execution_result before fetching rows.

Cancel work from another thread cancel-query

import threading
from databricks import sql

def run():
    try:
        cursor.execute("SELECT SUM(a.id - b.id) FROM range(1000000000) a CROSS JOIN range(100000000) b GROUP BY (a.id - b.id)")
    except sql.exc.RequestError:
        print("cancelled")

threading.Thread(target=run).start()
time.sleep(15)
cursor.cancel()

A synchronous execute call blocks its thread, so cancellation must come from another thread or control path. Handle the connector exception raised by the interrupted statement.

Commit or roll back several statements transactions

connection.autocommit = False

with connection.cursor() as cursor:
    try:
        cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
        cursor.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
        connection.commit()
    except Exception:
        connection.rollback()
        raise
    finally:
        connection.autocommit = True

Connections begin in autocommit mode. Transaction support also depends on the Databricks compute and table features backing the statements.

Create machine-to-machine credentials oauth-m2m

import os
from databricks.sdk.core import Config, oauth_service_principal
from databricks import sql

hostname = os.getenv("DATABRICKS_SERVER_HOSTNAME")

def credential_provider():
    return oauth_service_principal(Config(
        host=f"https://{hostname}",
        client_id=os.getenv("DATABRICKS_CLIENT_ID"),
        client_secret=os.getenv("DATABRICKS_CLIENT_SECRET"),
    ))

connection = sql.connect(
    server_hostname=hostname,
    http_path=os.getenv("DATABRICKS_HTTP_PATH"),
    credentials_provider=credential_provider,
)

Install databricks-sdk separately. A valid client secret is insufficient until the service principal is assigned to the workspace and granted access to the warehouse and data.

Inspect Unity Catalog metadata list-catalog-metadata

with connection.cursor() as cursor:
    print(cursor.catalogs().fetchall())
    print(cursor.schemas(catalog_name="main").fetchall())
    print(cursor.tables(catalog_name="main", schema_name="default").fetchall())
    print(cursor.columns(catalog_name="main", schema_name="default", table_name="users").fetchall())

These metadata methods return the cursor for immediate fetching. Pattern arguments accept percent wildcards when an exact catalog object name is unknown.

Put a local file into staging volume-ingestion

import os
from databricks import sql

local_dir = os.path.dirname(os.path.realpath("september.csv"))

with sql.connect(
    server_hostname=os.getenv("DATABRICKS_SERVER_HOSTNAME"),
    http_path=os.getenv("DATABRICKS_HTTP_PATH"),
    access_token=os.getenv("DATABRICKS_TOKEN"),
    staging_allowed_local_path=local_dir,
) as connection:
    with connection.cursor() as cursor:
        cursor.execute(
            "PUT 'september.csv' INTO 'stage://tmp/me@example.com/sales/september.csv' OVERWRITE"
        )

PUT and GET are restricted to the configured local directory tree. In 4.4.0, REMOVE no longer needs that setting because it touches only the remote staging location.

Select the Rust kernel client use-kernel-backend

# pip install "databricks-sql-connector[kernel]"
connection = sql.connect(
    server_hostname=host,
    http_path=http_path,
    access_token=token,
    use_kernel=True,
)

Install the kernel extra first; use_kernel=True does not fall back to Thrift when the native package is missing. Its wheel requires Python 3.10 or newer and the result path also needs PyArrow.

Alternatives

PackageRegistryPick it when
databricks-sdkPyPIUse it for jobs, clusters, workspace objects, and other REST APIs when running SQL is only a small part of the task.
databricks-sqlalchemyPyPIUse it when SQLAlchemy Core or ORM integration matters; the dialect was split from this connector in version 4.0.0.
pyodbcPyPIUse it when your fleet already carries ODBC drivers and one DB API client must connect to several database products.

More data guides

numpy · fsspec · pandas · sqlalchemy · pyarrow · lxml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.