Connecting to Lakebase, roles and permissions
kept in this browser
Edit this pageHow clients reach a Lakebase compute over TLS, the choice between one-hour OAuth tokens and Postgres passwords, and how Databricks identities become roles.
On this page14
What it is
A Lakebase compute is reached like any Postgres server: a host, port 5432, a database, a user and a password, over TLS. What is particular to Lakebase is where the password comes from and what the user is.
- The user is a Postgres role. It can stand for a Databricks identity — a user, a service principal or a group — or be a plain Postgres role with a password.
- The password is either a short-lived OAuth token issued by Databricks for that identity, or a native Postgres password that does not expire.
Any Postgres client works: psql, pgAdmin, DBeaver, JDBC and every language driver.
Why it exists
A database password is a long-lived secret that ends up in configuration files, CI variables and laptops, and nobody knows who else holds it. Databricks already knows who a user or a service principal is; issuing a token from that identity means the database login inherits the platform’s identity, its group memberships and its offboarding. When someone leaves, their Databricks access is removed and their tokens stop being issued.
Native passwords remain for the clients that cannot fetch a token every hour, and for the connection pooler, which does not accept tokens.
How it works
The connection string
Each compute has a host of the form ep-…, carrying the compute’s identifier; the regional form is ep-….database.<region>.cloud.databricks.com. TLS is mandatory:
host=ep-xxxx.database.us-east-1.cloud.databricks.com port=5432 dbname=databricks_postgres user=alice@example.com sslmode=require
The branch’s page in the Lakebase app shows the exact string for each compute and role.
OAuth tokens
A token is valid for one hour and is checked only when the connection is opened. An open connection is not closed when its token expires, but every new connection needs a current one. A token is scoped to one workspace.
databricks postgres generate-database-credential \
projects/shop/branches/production/endpoints/primary --output json
from databricks.sdk import WorkspaceClient
import psycopg
w = WorkspaceClient()
cred = w.postgres.generate_database_credential(
endpoint="projects/shop/branches/production/endpoints/primary"
)
with psycopg.connect(
host="ep-xxxx.database.us-east-1.cloud.databricks.com",
dbname="databricks_postgres",
user="alice@example.com",
password=cred.token,
sslmode="require",
) as conn:
print(conn.execute("select current_user").fetchone())
A long-running service must fetch a fresh token before opening new connections, typically in the pool’s connection factory rather than once at start-up.
Native passwords
A Postgres role with a password connects without Databricks in the path, and the password does not expire. For projects created since May 2026, password logins are off by default; they are switched on under the project’s settings, in Database connections. Store such passwords as secrets (see Secrets and credentials), never in code.
Every connection, whatever the login
Two limits apply to all connections: one idle for 24 hours is closed, and one open for three days may be closed. Clients should expect to reconnect.
Roles for Databricks identities
The project owner’s role exists from the start. For anyone else, a role is created for their Databricks identity, from the Lakebase app, the REST API, or SQL:
CREATE EXTENSION IF NOT EXISTS databricks_auth;
SELECT databricks_create_role('alice@example.com', 'USER');
SELECT databricks_create_role('data-apps', 'GROUP');
The type is USER, SERVICE_PRINCIPAL or GROUP. A new role receives LOGIN and nothing else: what it may read or write is granted separately, with ordinary Postgres grants. A group role is shared by its members: anyone in the Databricks group can log in as it. Group names are case-sensitive.
databricks_superuser
Lakebase does not hand out the real Postgres superuser. In its place is databricks_superuser, a role with CREATEDB, CREATEROLE and BYPASSRLS, which inherits pg_read_all_data, pg_write_all_data and pg_monitor. It cannot log in itself (NOLOGIN); roles are made members of it. The project owner is.
Membership is effectively full access to the data on that branch, row-level security included. Grant it to people who administer the database, not to applications.
Granting access
Permissions inside the database are plain Postgres:
GRANT USAGE ON SCHEMA orders TO "data-apps";
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA orders TO "data-apps";
ALTER DEFAULT PRIVILEGES IN SCHEMA orders GRANT SELECT, INSERT, UPDATE ON TABLES TO "data-apps";
These are separate from the project permissions (CAN CREATE, CAN USE, CAN MANAGE), which govern branches and computes, and from Unity Catalog grants, which govern warehouse queries on a registered catalog. See Privileges: GRANT, REVOKE, and DENY for the Unity Catalog side.
The connection pooler
Each compute has a built-in PgBouncer in transaction mode, on a host of the form <endpoint-id>-pooler…, accepting up to 10,000 client connections and sharing a much smaller number of Postgres connections among them. It suits serverless functions and applications with many short connections.
It has two restrictions that decide whether you can use it:
- It accepts password roles only, not OAuth tokens.
- In transaction mode, anything tied to a session breaks: SQL
PREPARE, session-levelSET,LISTEN/NOTIFY, advisory locks.pg_dumpand schema migrations must connect directly, not through the pooler.
Not supported
Native logical replication and tablespaces are not available. Changes leave Postgres through the Lakebase change data feed, from Postgres into Delta instead.
Example
A reporting service that logs in as a service principal, with a role that can only read one schema:
CREATE EXTENSION IF NOT EXISTS databricks_auth;
SELECT databricks_create_role('4f1c2e9a-…', 'SERVICE_PRINCIPAL'); -- the application ID
GRANT USAGE ON SCHEMA reporting TO "4f1c2e9a-…";
GRANT SELECT ON ALL TABLES IN SCHEMA reporting TO "4f1c2e9a-…";
The service authenticates to Databricks as the service principal, requests a token each time its pool opens a connection, and connects directly to the compute. It cannot write, and it cannot see any other schema.
Common mistakes
- Caching one token for the life of the process. It works for an hour, then every new connection fails. Refresh per connection.
- Pointing an OAuth client at the pooler. The pooler takes passwords only.
- Running migrations through the pooler. Session state and
pg_dumpneed a direct connection. - Granting
databricks_superuserto an application. It bypasses row-level security and can read and write everything. - Forgetting
sslmode=require. Connections without TLS are refused. - Assuming a new role can read.
databricks_create_rolegives login only; grants come after.