---
sidebar_position: 2
title: Connecting to MotherDuck
description: Create one or more connections to a MotherDuck database
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useBaseUrl from '@docusaurus/useBaseUrl';

There are two ways to connect to MotherDuck:

| Method | Client needed | Best for |
|--------|--------------|----------|
| **DuckDB SDK** | DuckDB client library | Python, Node.js, Java, CLI — full feature set, hybrid execution, local caching |
| **[Postgres Endpoint](/key-tasks/authenticating-and-connecting-to-motherduck/postgres-endpoint)** | Any PostgreSQL client | Thin clients, serverless environments, BI tools, languages without a DuckDB SDK |

This page covers connecting with the **DuckDB SDK**. For the Postgres endpoint, see [Postgres Endpoint](/key-tasks/authenticating-and-connecting-to-motherduck/postgres-endpoint).

## Connecting with the DuckDB SDK

A single DuckDB connection executes one query at a time, aiming to maximize the performance of that query, making reuse of a single connection both simple and performant.
We recommend starting with the simplest way of connecting to MotherDuck and running queries, and if that does not meet your requirements, to explore the advanced use-cases described in subsequent sections.

## Create a connection

<img src={useBaseUrl('/img/key-tasks/authenticating-and-connecting-to-motherduck/one-connection.png')} width="300" style={{maxWidth: '100%'}} />

The below code snippets show how to create a connection to a MotherDuck database from the CLI, Python, JDBC, and Node.js language APIs.

:::info
For security reasons, it's generally recommended to use environment variables to store your MotherDuck token rather than hardcoding it in your application.
:::

:::tip
The `INSERT INTO` statements below are for illustration only. For loading real data, do not insert rows one at a time — use bulk methods like `INSERT INTO ... SELECT` from files, `COPY`, or DataFrame-based approaches. See [Loading data into MotherDuck](/key-tasks/loading-data-into-motherduck/loading-data-into-motherduck.mdx) for recommended approaches.
:::

<Tabs>

<TabItem value="Python" label="Python">

To connect to your MotherDuck database, use `duckdb.connect("md:my_database_name")`. This will return a `DuckDBPyConnection` object that you can use to interact with your database.

There are two ways to provide your access token in Python to authenticate your user session.

<Tabs>
<TabItem value="Dict" label="Within a config dictionary">

```python
import duckdb

# Create connection to your default database
conn = duckdb.connect("md:my_db", config={"motherduck_token" :<your-motherduck-token>}) # Optionally, import your token from a .env file

# Run query
conn.sql("CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER)")
conn.sql("INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2)")
res = conn.sql("SELECT * FROM items")

# Close the connection
conn.close()
```

</TabItem>

<TabItem value="String" label="Included in the connection string">

```python
import duckdb

# Create connection to your default database
conn = duckdb.connect(f"md:my_db?motherduck_token={<your-motherduck-token>}") # Optionally, import your token directly from a .env file

# Run query
conn.sql("CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER)")
conn.sql("INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2)")
res = conn.sql("SELECT * FROM items")

# Close the connection
conn.close()
```

</TabItem>
</Tabs>

</TabItem>

<TabItem value="JDBC" label="JDBC">

To connect to your MotherDuck database, you can create a `Connection` by using the `"jdbc:duckdb:md:databaseName"` connection string format. For authentication, you need to provide a MotherDuck token.

There are two ways to provide the token:
<Tabs>
<TabItem value="Property" label="As a connection property">

```java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import java.util.Properties;

// Create properties with your MotherDuck token
Properties props = new Properties();
props.setProperty("motherduck_token", "<your-motherduck-token>");

// Create connection to your database
try (Connection conn = DriverManager.getConnection("jdbc:duckdb:md:my_db", props);
     Statement stmt = conn.createStatement()) {

    stmt.executeUpdate("CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER)");
    stmt.executeUpdate("INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2)");

    try (ResultSet rs = stmt.executeQuery("SELECT * FROM items")) {
        while (rs.next()) {
            System.out.println("Item: " + rs.getString(1) + " costs " + rs.getInt(3));
        }
    }
}
```

</TabItem>
<TabItem value="String" label="As part of the connection string">

```java
// Create connection with token in the connection string
try (Connection conn = DriverManager.getConnection("jdbc:duckdb:md:my_db?motherduck_token=<your-motherduck-token>");
     Statement stmt = conn.createStatement()) {

    stmt.executeUpdate("CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER)");
    stmt.executeUpdate("INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2)");

    try (ResultSet rs = stmt.executeQuery("SELECT * FROM items")) {
        while (rs.next()) {
            System.out.println("Item: " + rs.getString(1) + " costs " + rs.getInt(3));
        }
    }
}
```

:::info
If an environment variable named `motherduck_token` is set, it will be used automatically.
:::
</TabItem>
</Tabs>
</TabItem>

<TabItem value="NodeJS" label="Node.js">

To connect to your MotherDuck database, you can create a `DuckDBInstance` with the `'md:databaseName'` connection string format. For authentication, you need to provide a MotherDuck token.

There are two ways to provide the token:

<Tabs>
<TabItem value="Dict" label="Within a config dictionary">

```javascript
import { DuckDBInstance } from '@duckdb/node-api';

// Create connection to your default database
const instance = await DuckDBInstance.create('md:my_db', {
  motherduck_token: '<your-motherduck-token>',
});
const conn = await instance.connect();

// Run queries
await conn.run('CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER)');
await conn.run("INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2)");
const result = await conn.runAndReadAll('SELECT * FROM items');
console.table(result.getRowObjects());
```

</TabItem>
<TabItem value="String" label="Included in the connection string">

```javascript
import { DuckDBInstance } from '@duckdb/node-api';

// Create connection to your default database
const instance = await DuckDBInstance.create('md:my_db?motherduck_token=<your-motherduck-token>');
const conn = await instance.connect();

// Run queries
await conn.run('CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER)');
await conn.run("INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2)");
const result = await conn.runAndReadAll('SELECT * FROM items');
console.table(result.getRowObjects());
```

:::info
If an environment variable named `motherduck_token` is set, it's used automatically.
:::

</TabItem>
</Tabs>

</TabItem>

<TabItem value="CLI" label="CLI">

To connect to your MotherDuck database, run `duckdb md:<database_name>`.

```shell
duckdb "md:my_db"
```

Now, you will enter the DuckDB interactive terminal to interact with your database.

```sql
D CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER);
D INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2);
D SELECT * FROM items;
```

</TabItem>
</Tabs>

## Session names

The `session_name` connection string parameter lets you give your session a name. You can set it in the connection string (`md:my_db?session_name=my_label`) or as a DuckDB setting before connecting to MotherDuck (`SET motherduck_session_name='my_label'`).

:::note
The older `session_hint` parameter still works as an alias for `session_name`.
:::

### Read scaling with session names

If you are planning on multiple end users connecting with a [Read Scaling Token](/documentation/key-tasks/authenticating-and-connecting-to-motherduck/read-scaling/read-scaling.mdx), ensure each user can get a dedicated backend (up to the maximum configured flock size) by passing a `session_name` in the connection string.
Session names ensure that all the queries from the same end user are routed to the same backend duckling, even if they originate from different services/servers. This allows for optimal caching and resource allocation for each specific user's needs.

After establishing the connection, it can be used the same way as any DuckDB/MotherDuck connection -- to run queries, and then either be closed explicitly or go out of scope, as in the examples above.

### Annotating queries with session names

The `session_name` value appears in the `SESSION_NAME` column of [query history](/sql-reference/motherduck-sql-reference/md_information_schema/query_history/), making it easy to identify and group queries. This works for both read scaling and read/write connections.


<Tabs>

<TabItem value="Python" label="Python">

```python
import duckdb

# Create a connection and allocate a stable backend for user123.
con = duckdb.connect(
    "md:my_db?session_name=user123",
    config = {'motherduck_token': '<your-motherduck-read-scaling-token>'} )
```

</TabItem>

<TabItem value="JDBC" label="JDBC">

```java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import java.util.Properties;

// Create properties with your MotherDuck token
Properties props = new Properties();
props.setProperty("motherduck_token", "<your-motherduck-read-scaling-token>");

// Create a connection and allocate a stable backend for user123.
try (Connection conn = DriverManager.getConnection("jdbc:duckdb:md:my_db?session_name=user123", props)) {
    // ...
}
```

</TabItem>

<TabItem value="duckdb-node-api" label="Node.js">

```javascript
import { DuckDBInstance } from '@duckdb/node-api';

// Create a connection and allocate a stable backend for user123.
const instance = await DuckDBInstance.create(
    'md:my_db?session_name=user123',
    { motherduck_token: '<your-motherduck-read-scaling-token>' } );
// ...
```

</TabItem>

</Tabs>



## Multiple connections and the database instance cache

DuckDB clients in Python, Go, R, JDBC, and ODBC prevent redundant reinitialization by keeping instances of database-global context cached by the database path.

When connecting to MotherDuck, the instance is cached for an additional 15 minutes after the last connection is closed (see [Setting Custom Database Instance Cache TTL](#setting-custom-database-instance-cache-time-ttl) for how to override this value).
For an application that creates and closes connections frequently, this could provide a significant speedup for connection creation, as the same catalog data can be reused across connections.

This means that only the first of multiple connections to the same database will take the time to load the MotherDuck extension, verify its signature, and fetch the catalog metadata.

<Tabs>
<TabItem value="Python" label="Python">

```python
con1 = duckdb.connect("md:my_db")	// MotherDuck catalog fetched
con2 = duckdb.connect("md:my_db")	// MotherDuck catalog reused
```

</TabItem>
<TabItem value="Java" label="Java">

```java
// Create properties with your MotherDuck token
Properties props = new Properties();
props.setProperty("motherduck_token", "<your-motherduck-token>");

try (var con1 = DriverManager.getConnection("jdbc:duckdb:md:my_db", props); // MotherDuck catalog fetched
     var con2 = DriverManager.getConnection("jdbc:duckdb:md:my_db", props); // MotherDuck catalog reused
     ) {
    // ...
}
```

</TabItem>
<TabItem value="duckdb-node-api" label="Node.js">

:::warning Node.js does not cache instances automatically
Unlike some other clients, the Node.js client (`@duckdb/node-api`) does **not** cache database instances by default. Each call to `DuckDBInstance.create()` creates a new instance, which means the MotherDuck extension is reloaded and the catalog metadata is re-fetched every time. Depending on the size of your catalog this can cause significant connection delays.

To avoid this, use `DuckDBInstance.fromCache()` or create a `DuckDBInstanceCache` as shown below.
:::

In Node.js, you must explicitly opt in to instance caching by using `DuckDBInstance.fromCache()` instead of `DuckDBInstance.create()`. This uses a built-in default cache to ensure only one instance is created per database path, avoiding reloading the MotherDuck extension and re-fetching catalog metadata on subsequent connections.

```javascript
import { DuckDBInstance } from '@duckdb/node-api';

// First call creates the instance and fetches the MotherDuck catalog
const instance = await DuckDBInstance.fromCache('md:my_db', {
  motherduck_token: '<your-motherduck-token>',
});
const connection1 = await instance.connect();

// Second call reuses the cached instance — no reinitialization needed
const instance2 = await DuckDBInstance.fromCache('md:my_db');
const connection2 = await instance2.connect();
```

For more control, you can create your own `DuckDBInstanceCache`:

```javascript
import { DuckDBInstanceCache } from '@duckdb/node-api';

const cache = new DuckDBInstanceCache();

// Retrieves an existing instance or creates one if it doesn't exist
const instance = await cache.getOrCreateInstance('md:my_db');
const connection = await instance.connect();
```

</TabItem>
</Tabs>


## Setting custom database instance cache time (TTL)

By default, connections to MotherDuck established through the database instance caching supporting DuckDB APIs will reuse the same database instance for 15 minutes after the last connection is closed.
In some cases, you may want to make that period longer (to avoid the redundant reinitialization) or shorter (to connect to the same database with a different configuration).

The database TTL value can be set either at the initial connection time, or by using the `SET` command at any point.
Any valid [DuckDB Instant part specifiers](https://duckdb.org/docs/stable/sql/functions/datepart.html#part-specifiers-usable-as-date-part-specifiers-and-in-intervals) can be used for the TTL value, for example '5s', '3m', or '1h'.

:::note
The examples below assume you have configured your MotherDuck token using one of the authentication methods described in the [Create a connection](#create-a-connection) section above.
:::

<Tabs>
<TabItem value="Python" label="Python">

```python
con = duckdb.connect("md:my_db?dbinstance_inactivity_ttl=1h")
con.close()

# different database connection string (without `?dbinstance_inactivity_ttl=1h`), no instance cached; TTL is 15 minutes (default)
con2 = duckdb.connect("md:my_db")

# allow the database instance to expire immediately
con2.execute("SET motherduck_dbinstance_inactivity_ttl='0s'")

# the database instance can only expire after the last connection is closed
con2.close()

# new database instance with a new TTL (the 15 minute default)
con3 = duckdb.connect("md:my_db")
con3.close()

# the last TTL for this database was 15 minutes; the cached database instance will be reused
con4 = duckdb.connect("md:my_db")
```

</TabItem>
<TabItem value="Java" label="Java">

The TTL can be set either through the connection string or through Properties. However, be careful when using Properties as the database instance cache is keyed by the connection string. This means that if you change the TTL in Properties between connections, you'll get an error as it's trying to connect to the same database with different configurations.

Here's an example that will fail:

```java
Properties props = new Properties();
props.setProperty("motherduck_dbinstance_inactivity_ttl", "2m");

// First connection works fine
try (var con = DriverManager.getConnection("jdbc:duckdb:md:my_db", props)) {
    // TTL is set to 2m
}

// Changing TTL in properties will fail
props.setProperty("motherduck_dbinstance_inactivity_ttl", "5m");
try (var con = DriverManager.getConnection("jdbc:duckdb:md:my_db", props)) {
    // This will throw: "Can't open a connection to same database file 
    // with a different configuration than existing connections"
}
```

For this reason, it's generally safer to set the TTL through the connection string:

```java
// Set TTL through connection string
try (var con = DriverManager.getConnection("jdbc:duckdb:md:my_db?dbinstance_inactivity_ttl=1h")) {
    // TTL is set to 1h
}

// Different TTL creates a new instance
try (var con = DriverManager.getConnection("jdbc:duckdb:md:my_db?dbinstance_inactivity_ttl=30m")) {
    // This works - creates a new instance with 30m TTL
}

// Can also set TTL using SQL
try (var con = DriverManager.getConnection("jdbc:duckdb:md:my_db");
     var st = con.createStatement()) {
    // allow the database instance to expire immediately
    st.executeUpdate("SET motherduck_dbinstance_inactivity_ttl='0s'");
}
```

:::note
When using Properties, you must include the `motherduck_` prefix for the TTL property name (i.e., `motherduck_dbinstance_inactivity_ttl`). This prefix is only optional when passing the TTL through the connection string.
:::

</TabItem>
<TabItem value="duckdb-node-api" label="NodeJS">

```javascript
import { DuckDBInstance } from '@duckdb/node-api';

// Set TTL to 1 hour through the connection string
const instance = await DuckDBInstance.fromCache('md:my_db?dbinstance_inactivity_ttl=1h');
const conn = await instance.connect();

// Or set the TTL using SQL after connecting
await conn.run("SET motherduck_dbinstance_inactivity_ttl='30m'");

// Allow the database instance to expire immediately after the connection closes
await conn.run("SET motherduck_dbinstance_inactivity_ttl='0s'");
```

</TabItem>
</Tabs>

## Connect to multiple databases

If you need to connect to MotherDuck and run one or more queries in succession on the same account, you can use a [single database connection](#create-a-connection). If you want to connect to another database in the same account, you can either [reuse the same connection](#example-1-reuse-the-same-duckdb-connection), or [create copies](#example-2-create-copies-of-the-initial-duckdb-connection) of the connection.

<Tabs>

<TabItem value="Python" label="Python">

If you need to connect to multiple databases, you can either directly reuse the same `DuckDBPyConnection` instance, or create copies of the connection using the `.cursor()` method.

:::note
`FROM <table name>` is a shorthand version of
`SELECT * FROM <table name>`.
:::

### Example 1: Reuse the same DuckDB connection

<img src={useBaseUrl('/img/key-tasks/authenticating-and-connecting-to-motherduck/one-connection.png')} width="300" style={{maxWidth: '100%'}} />

To connect to different databases in the same MotherDuck account, you can use the same connection object and fully qualify the names of the tables in your query.

```python
conn = duckdb.connect("md:my_db")

res1 = conn.sql("FROM my_db1.main.tbl")
res2 = conn.sql("FROM my_db2.main.tbl")
res3 = conn.sql("FROM my_db3.main.tbl")

conn.close()
```

### Example 2: Create copies of the initial DuckDB connection

<img src={useBaseUrl('/img/key-tasks/authenticating-and-connecting-to-motherduck/one-connection-threads.png')} width="300" style={{maxWidth: '100%'}} />

`conn.cursor()` returns a copy of the DuckDB connection, with a reference to the existing DuckDB database instance. Closing the original connection also closes all associated cursors.

```python
conn = duckdb.connect("md:my_db")

cur1 = conn.cursor()
cur2 = conn.cursor()
cur3 = conn.cursor()

cur1.sql("USE my_db1")
cur2.sql("USE my_db2")
cur3.sql("USE my_db3")

res = []
for cur in [cur1, cur2, cur3]:
  res.append(cur.sql("SELECT * FROM tbl"))

# This closes the original DuckDB connection and all cursors
conn.close()
```

:::note
`duckdb.connect(path)` creates and caches a DuckDB instance. Subsequent calls with the same path reuse this instance. New connections to the same instance are independent, similar to `conn.cursor()`, but closing one doesn't affect others. To create a new instance instead of using the cached one, make the path unique (e.g., `md:my_db?user=<unique ID>`).
:::

### Example 3: Create multiple connections

<img src={useBaseUrl('/img/key-tasks/authenticating-and-connecting-to-motherduck/multiple-connections.png')} width="300" style={{maxWidth: '100%'}} />

You can also create multiple connections to the same MotherDuck account using different DuckDB instances. However, keep in mind that each connection takes time to establish, and if connection times are an important factor for your application, it might be beneficial to consider [Example 1](#example-1-reuse-the-same-duckdb-connection) or [Example 2](#example-2-create-copies-of-the-initial-duckdb-connection).

:::note
If you need to run queries on separate connections in quick succession, instead of opening and closing a connection for every query, we recommend using a Connection Pool ([Python](/docs/key-tasks/authenticating-and-connecting-to-motherduck/multithreading-and-parallelism/multithreading-and-parallelism-python#connection-pooling), [JDBC](/docs/key-tasks/authenticating-and-connecting-to-motherduck/multithreading-and-parallelism/multithreading-and-parallelism-jdbc#connection-pooling) or [Node.js](/docs/key-tasks/authenticating-and-connecting-to-motherduck/multithreading-and-parallelism/multithreading-and-parallelism-nodejs#connection-pooling)).
:::

```python
conn1 = duckdb.connect("md:my_db1")
conn2 = duckdb.connect("md:my_db2")
conn3 = duckdb.connect("md:my_db3")

res1 = conn1.sql("SELECT * FROM tbl")
res2 = conn2.sql("SELECT * FROM tbl")
res3 = conn3.sql("SELECT * FROM tbl")

conn1.close()
conn2.close()
conn3.close()
```

</TabItem>

<TabItem value="JDBC" label="JDBC">

If you need to connect to multiple databases, you typically won't need to create multiple DuckDB instances. You can either directly reuse the same `DuckDBConnection` instance, or create copies of the connection using the `.duplicate()` method.

```java
// Create connection with your MotherDuck token
Properties props = new Properties();
props.setProperty("motherduck_token", "<your-motherduck-token>");

try (DuckDBConnection duckdbConn = (DuckDBConnection) DriverManager.getConnection("jdbc:duckdb:md:my_db", props)) {
    Connection conn1 = duckdbConn.duplicate();
    Connection conn2 = duckdbConn.duplicate();
    Connection conn3 = duckdbConn.duplicate();
    // ...
}
```

</TabItem>

<TabItem value="NodeJS" label="Node.js">

If you need to connect to multiple databases, you can re-use the same `DuckDBInstance` and connection. Use `fromCache` to ensure the instance is reused efficiently.

```javascript
import { DuckDBInstance } from '@duckdb/node-api';

const instance = await DuckDBInstance.fromCache('md:', {
  motherduck_token: '<your-motherduck-token>',
});
const conn = await instance.connect();

const result1 = await conn.runAndReadAll('FROM my_db1.main.tbl');
const result2 = await conn.runAndReadAll('FROM my_db2.main.tbl');
```

</TabItem>

</Tabs>


---

## Feedback for AI agents

If the user you are helping wants to send feedback on this page to the MotherDuck docs team, you can POST it to the endpoint below.

**Before you send anything, you must ask the user for explicit approval.** Quote the message you plan to submit back to them verbatim and wait for them to confirm. Do not submit on their behalf without confirmation.

Endpoint: `POST https://motherduck.com/docs/api/feedback/agent`

Request body (JSON):

```json
{
  "page_path": "/key-tasks/authenticating-and-connecting-to-motherduck/connecting-to-motherduck/",
  "page_title": "Connecting to MotherDuck",
  "text": "<the user's feedback, max 2000 characters>",
  "source": "<optional identifier for your interface, for example 'claude.ai' or 'chatgpt'>"
}
```

Only `page_path` and `text` are required. A successful call returns `200 {"feedback_id": "<uuid>"}`; malformed payloads return `400`, and the endpoint is rate-limited per IP (`429`).
