How to Connect to Snowflake from Go
Snowflake has exactly one Go driver: the official gosnowflake from Snowflake itself. It implements the standard database/sql interface, so you connect, query, and scan rows the same way you would against any other SQL database in Go. The parts that trip people up are Snowflake-specific: the account identifier format, the move to v2 of the driver in March 2026, and the fact that Snowflake now blocks single-factor password auth for new accounts, which pushes you toward key-pair (JWT) authentication.
The options
| Package | Import path | Interface | Version (as of June 2026) |
|---|---|---|---|
| gosnowflake v2 | github.com/snowflakedb/gosnowflake/v2 | database/sql | v2.1.0 |
| gosnowflake v1 | github.com/snowflakedb/gosnowflake | database/sql | v1.19.1 |
There is no third-party alternative worth considering. Snowflake speaks its own protocol over HTTPS, not the Postgres or MySQL wire protocol, so the official driver is the only one that understands it.
v1 vs v2: Version 2.0.0 was released on March 3rd, 2026 and is a major version with breaking changes. v1 (currently v1.19.1) is still maintained and receives fixes, so existing code does not have to migrate immediately. New projects should start on v2 because that is where active development lives. The two cannot be imported under the same name in the same module, so pick one. The v2 changes that matter to most code:
- Import path gains
/v2(github.com/snowflakedb/gosnowflake/v2). - Arrow batches moved to a separate sub-package,
gosnowflake/v2/arrowbatches, so you only pull the Arrow dependency if you use it. - Config fields renamed:
KeepSessionAliveis nowServerSessionKeepAlive, andInsecureModeis replaced byDisableOCSPChecks.DisableTelemetrywas removed (use theCLIENT_TELEMETRY_ENABLEDsession parameter). - The skip-registration env var typo was fixed:
GOSNOWFLAKE_SKIP_REGISTERATIONbecameGOSNOWFLAKE_SKIP_REGISTRATION.
The rest of this guide uses v2.
Install
go get github.com/snowflakedb/gosnowflake/v2The account identifier trap
Snowflake's biggest connection gotcha is the account identifier. The current recommended format is <organization>-<account_name> with a hyphen, not a dot:
myorg-myaccount
You will also see the legacy format that includes a region and cloud, like xy12345.eu-central-1.aws. Both still work, but the org-account form is what Snowflake recommends today. The value goes after the @ in the DSN. A frequent mistake is pasting the full account URL (myorg-myaccount.snowflakecomputing.com) as the identifier; use just the identifier part, or pass the full hostname explicitly via the Config.Host field.
You can find your account identifier in the Snowsight UI under your account menu, or by running SELECT CURRENT_ORGANIZATION_NAME(), CURRENT_ACCOUNT_NAME();.
Connect with a DSN
The driver registers itself under the name snowflake. The DSN format is:
username[:password]@<account_identifier>/dbname/schemaname?warehouse=wh&role=myrole
package main
import (
"database/sql"
"log"
_ "github.com/snowflakedb/gosnowflake/v2"
)
func main() {
dsn := "jsmith:mypassword@myorg-myaccount/mydb/public?warehouse=compute_wh&role=analyst"
db, err := sql.Open("snowflake", dsn)
if err != nil {
log.Fatal(err)
}
defer db.Close()
if err := db.Ping(); err != nil {
log.Fatal(err)
}
var version string
if err := db.QueryRow("SELECT CURRENT_VERSION()").Scan(&version); err != nil {
log.Fatal(err)
}
log.Printf("connected to Snowflake %s", version)
}Two things mirror every other database/sql driver and are worth repeating:
sql.Opendoes not open a connection. It validates the DSN and returns a handle. The first real network round-trip happens onPingor the first query, which is why thePingabove is how you actually confirm the credentials and warehouse are valid.- The blank import (
_ "...gosnowflake/v2") is what registers thesnowflakedriver name. Forget it andsql.Openreturnssql: unknown driver "snowflake".
Building the DSN safely
Passwords and identifiers with special characters need escaping. Rather than concatenating strings, build a Config and let the driver produce a correct DSN:
import sf "github.com/snowflakedb/gosnowflake/v2"
cfg := &sf.Config{
Account: "myorg-myaccount",
User: "jsmith",
Password: "mypassword",
Database: "mydb",
Schema: "public",
Warehouse: "compute_wh",
Role: "analyst",
}
dsn, err := sf.DSN(cfg)
if err != nil {
log.Fatal(err)
}
db, err := sql.Open("snowflake", dsn)Key-pair (JWT) authentication
As of late 2025, Snowflake blocks new connections that use a password as the only factor. For programmatic access (which is what a Go service is), the recommended path is key-pair authentication. You generate an RSA key pair, register the public key on the Snowflake user, and the driver signs a JWT with the private key.
Generate the key pair:
# 2048-bit PKCS8 private key
openssl genpkey -algorithm RSA \
-pkeyopt rsa_keygen_bits:2048 \
-pkeyopt rsa_keygen_pubexp:65537 | \
openssl pkcs8 -topk8 -outform der -nocrypt > rsa_key.p8
# matching public key
openssl pkey -pubout -inform der -outform der \
-in rsa_key.p8 -out rsa_key.pubRegister the public key on the user (base64 of the DER public key, no header lines):
ALTER USER jsmith SET RSA_PUBLIC_KEY='MIIBIjANBgkq...';Then load and parse the private key in Go and pass it via Config:
import (
"crypto/rsa"
"crypto/x509"
"database/sql"
"log"
"os"
sf "github.com/snowflakedb/gosnowflake/v2"
)
func connect() (*sql.DB, error) {
der, err := os.ReadFile("rsa_key.p8")
if err != nil {
return nil, err
}
parsed, err := x509.ParsePKCS8PrivateKey(der)
if err != nil {
return nil, err
}
privKey := parsed.(*rsa.PrivateKey)
cfg := &sf.Config{
Account: "myorg-myaccount",
User: "jsmith",
Authenticator: sf.AuthTypeJwt,
PrivateKey: privKey,
Database: "mydb",
Schema: "public",
Warehouse: "compute_wh",
}
dsn, err := sf.DSN(cfg)
if err != nil {
return nil, err
}
return sql.Open("snowflake", dsn)
}Note that Go's standard library does not support passphrase-encrypted PKCS8 keys, so generate the key with -nocrypt as above, or decrypt it in your application before parsing. The JWT is recreated on each retry and is short-lived, so you do not manage token expiry yourself.
For SSO in interactive contexts, set Authenticator: sf.AuthTypeExternalBrowser, but that is for human logins, not a server.
Parameter binding
Snowflake uses positional ? placeholders with database/sql:
rows, err := db.Query(
"SELECT id, email FROM users WHERE country = ? AND created_at > ?",
"CH", "2026-01-01",
)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int64
var email string
if err := rows.Scan(&id, &email); err != nil {
log.Fatal(err)
}
// use id, email
}
if err := rows.Err(); err != nil { // catches errors that ended iteration
log.Fatal(err)
}Always defer rows.Close() and check rows.Err() after the loop. A for rows.Next() loop can stop because the data ended or because an error occurred mid-stream, and only rows.Err() distinguishes the two.
Identifiers come back uppercase
Snowflake folds unquoted identifiers to uppercase. A column written as select email comes back as EMAIL in result metadata, and a table created as users is stored as USERS. This matters when you read column names dynamically or build a tool that lists tables. If you created an object with quotes to force mixed case (CREATE TABLE "myTable"), you must quote it everywhere, including inside the DSN, which means escaping the inner quotes. Avoid mixed-case identifiers unless you have a reason.
The "no active warehouse" error
000606: No active warehouse selected in the current session.
This is not a connection failure. It means you connected but never selected a warehouse, so Snowflake has nowhere to run the query. Set warehouse= in the DSN or Warehouse in the Config, and make sure the role you connect with has USAGE on that warehouse. Unlike a Postgres or MySQL server, Snowflake separates storage from compute, and a query needs a running warehouse to execute.
Connection pooling
*sql.DB is a pool, and it is safe for concurrent use, so create one and share it across goroutines. Snowflake connections are HTTPS sessions rather than long-lived TCP connections to a single server, so the tuning advice differs slightly from a traditional database:
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(0) // sessions are managed server-side; no hard need to recycleEach open connection corresponds to a Snowflake session, and sessions have their own timeout managed by the server. If your workload is bursty, keep MaxIdleConns low so you are not holding idle sessions. For long-running services that keep connections parked, set ServerSessionKeepAlive: true in the Config to stop the server from expiring idle sessions out from under you.
Context and cancellation
Use the context-aware methods so a cancelled request or a timeout actually cancels the running query in Snowflake, rather than leaking a warehouse-consuming query:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
rows, err := db.QueryContext(ctx, "SELECT count(*) FROM large_table")Because Snowflake bills for warehouse time, cancelling abandoned queries is not just hygiene, it has a direct cost impact.
Common errors
| Error | Likely cause |
|---|---|
sql: unknown driver "snowflake" | Missing the blank import of the driver package |
260008: account is empty | Account identifier missing or malformed in the DSN |
390100: Incorrect username or password | Wrong credentials, or password auth blocked (switch to key-pair) |
JWT token is invalid | Public key not registered, key mismatch, or clock skew on the client |
000606: No active warehouse selected | No warehouse set, or role lacks USAGE on it |
390201: cannot perform operation; no database selected | database not set and queries use unqualified names |
Where Mako fits
Once you can connect, you still need to explore the data: list tables, check column types, write and iterate on queries. Mako connects to Snowflake (and PostgreSQL, MySQL, ClickHouse, BigQuery, and more) with AI-powered autocomplete, so you can prototype the exact queries your Go service will run before you hardcode them. It is a read and query tool, not a schema-management console, so you will still use Snowsight or SQL for CREATE/ALTER work.
For loading data into Snowflake first, see our import CSV to Snowflake and import JSON to Snowflake guides. To connect from other languages, see connect to Snowflake from Python and connect to Snowflake from Node.js.
Mako connects to Snowflake with AI-powered autocomplete. Try it free at mako.ai.
Skip the terminal. Use Mako.
Connect your database, write queries with AI assistance, and import/export data in clicks. Free to start.