How to Connect to Snowflake from Python

6 min readSnowflake

Connecting to Snowflake from Python has one official answer: snowflake-connector-python, maintained by Snowflake and implementing the Python DB API 2.0. There is no community-vs-official driver debate like with MySQL or ClickHouse. What there is instead: an authentication landscape that changed significantly in 2025, when Snowflake started blocking single-factor password logins. If you are setting up a new programmatic connection today, you should plan for key-pair authentication from the start, not passwords.

The packages

PackageWhat it isVersion (as of June 2026)
snowflake-connector-pythonOfficial DB API 2.0 driver4.6.0, Python 3.10+
snowflake-snowpark-pythonDataFrame API that pushes compute to Snowflake1.52.0
snowflake-sqlalchemySQLAlchemy dialect on top of the connector1.10.0

This guide focuses on the connector. Snowpark is worth knowing about: it gives you a pandas-like DataFrame API where operations compile to SQL and run in the warehouse instead of pulling data to your machine. If your workload is "transform large tables", Snowpark is often the better tool. If it is "run queries, fetch results", the connector is simpler.

Install:

pip install snowflake-connector-python

The account identifier (where most first attempts fail)

Snowflake has no host or port parameter. You pass an account identifier and the connector builds the URL https://<account>.snowflakecomputing.com. The preferred format is organization-account:

myorg-account123

You can find it in Snowsight under your account menu, or with SELECT CURRENT_ORGANIZATION_NAME() || '-' || CURRENT_ACCOUNT_NAME();. Two traps:

  • The legacy locator format (xy12345.us-east-1) still appears in old tutorials and still works, but Snowflake documents it as not recommended. Use the org-account form.
  • Copying from the browser URL. If your Snowsight URL is https://app.snowflake.com/myorg/account123/..., the account parameter is myorg-account123 with a hyphen, not a slash, and without any .snowflakecomputing.com suffix. Passing the full URL fails with a DNS or 404-style error.

Authentication: passwords are no longer enough

Since November 2025, Snowflake blocks single-factor password authentication. Human users with passwords must enroll in MFA; service users cannot use passwords at all. For scripts and applications, that leaves you with these options, in rough order of preference:

  1. Key-pair authentication -- the standard for service accounts and any unattended code
  2. External browser SSO (authenticator="externalbrowser") -- for humans running ad-hoc scripts on machines with a browser
  3. OAuth / programmatic access tokens -- when you are integrating with an identity provider

Key-pair auth setup

Generate an RSA key pair (Snowflake requires PKCS#8 format for the private key):

# Encrypted private key (you'll be prompted for a passphrase)
openssl genrsa 2048 | openssl pkcs8 -topk8 -v2 aes256 -inform PEM -out rsa_key.p8
 
# Public key to register in Snowflake
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub

Register the public key on your Snowflake user (strip the PEM header/footer and line breaks, or paste the whole block in Snowsight):

ALTER USER etl_service SET RSA_PUBLIC_KEY='MIIBIjANBgkq...';

Then connect:

import snowflake.connector
 
conn = snowflake.connector.connect(
    account="myorg-account123",
    user="ETL_SERVICE",
    private_key_file="/path/to/rsa_key.p8",
    private_key_file_pwd="key-passphrase",
    warehouse="COMPUTE_WH",
    database="ANALYTICS",
    schema="PUBLIC",
    role="ETL_ROLE",
)
 
cur = conn.cursor()
cur.execute("SELECT CURRENT_VERSION()")
print(cur.fetchone())
conn.close()

The private_key_file parameter reads and decrypts the key for you (the older pattern of loading the key with cryptography and passing DER bytes to private_key still works, but is no longer necessary). For humans, swap the key parameters for authenticator="externalbrowser" and the connector opens your identity provider's login page.

connections.toml

The connector reads named connections from ~/.snowflake/connections.toml, which keeps credentials out of code:

[etl]
account = "myorg-account123"
user = "ETL_SERVICE"
private_key_file = "/path/to/rsa_key.p8"
warehouse = "COMPUTE_WH"
database = "ANALYTICS"
conn = snowflake.connector.connect(connection_name="etl")

Context: warehouse, database, schema, role

A Snowflake session has four context settings, and queries fail in confusing ways when they are missing. The big one is the warehouse: if no warehouse is set (none passed, no user default), any query that needs compute fails with No active warehouse selected in the current session. Set warehouse= in the connection or run cur.execute("USE WAREHOUSE COMPUTE_WH").

Remember that a running warehouse bills per second with a 60-second minimum, and auto-suspends after an idle period (default 10 minutes on new warehouses). A connection left open does not keep the warehouse alive by itself; the first query after suspension auto-resumes it with a second or two of latency. That is normal, not a bug.

Query parameters

The connector defaults to pyformat style (%(name)s), and you can switch to qmark (?) globally. Never use f-strings to build SQL:

# pyformat (default)
cur.execute(
    "SELECT * FROM orders WHERE status = %(status)s AND amount > %(min)s",
    {"status": "shipped", "min": 100},
)
 
# qmark -- set once before connecting
snowflake.connector.paramstyle = "qmark"
cur.execute("SELECT * FROM orders WHERE status = ? AND amount > ?", ("shipped", 100))

Snowflake's own docs recommend qmark for server-side binding, which matters for executemany batch inserts: with qmark the connector sends one batched statement instead of interpolating values client-side.

pandas integration

Install the extra (it pulls in pyarrow):

pip install "snowflake-connector-python[pandas]"

Reading is built into the cursor, and writing has a dedicated helper:

# Read
cur.execute("SELECT * FROM orders WHERE order_date >= '2026-01-01'")
df = cur.fetch_pandas_all()          # one DataFrame
# or cur.fetch_pandas_batches()     # iterator of DataFrames for large results
 
# Write
from snowflake.connector.pandas_tools import write_pandas
write_pandas(conn, df, table_name="ORDERS_STAGED", auto_create_table=True)

write_pandas stages the DataFrame as Parquet files and runs COPY INTO under the hood, which is dramatically faster than executemany INSERTs for anything beyond a few thousand rows. One gotcha: unquoted Snowflake identifiers are uppercase, and write_pandas quotes column names from the DataFrame as-is by default. Lowercase DataFrame columns produce case-sensitive quoted columns unless you uppercase them first or pass quote_identifiers=False.

Common errors

ErrorCause
250001: Could not connect to Snowflake backend / DNS failureWrong account identifier format
No active warehouse selectedNo warehouse in connection params or user defaults
390144: JWT token is invalidPublic key on the user does not match the private key, or wrong user
Password was not specified with a service userSingle-factor password auth is blocked; switch to key-pair
Authentication token has expired mid-jobLong-running session; set client_session_keep_alive=True for jobs that hold connections over 4 hours

Verifying your data

After connecting, you usually want to browse what is in the warehouse. Snowsight works; a desktop client is faster for jumping between databases. We compared the options in Best Snowflake GUI Clients. For loading data, see Import CSV to Snowflake and Import JSON to Snowflake.

Mako connects to Snowflake with AI-powered autocomplete. Try it free at mako.ai.

Mako — open source

Skip the terminal. Use Mako.

Connect your database, write queries with AI assistance, and import/export data in clicks. Free to start.