> ## Documentation Index
> Fetch the complete documentation index at: https://docs.danubeai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# PostgreSQL

> Let agents inspect schemas, run read-only SQL, read query plans and see what is slow or blocked in your Postgres database

The PostgreSQL connector works with any server that speaks the Postgres protocol: self-hosted Postgres, Amazon RDS and Aurora Postgres, Google Cloud SQL, Azure Database for PostgreSQL, Supabase (direct connection), Neon and CockroachDB. Extensions such as pgvector and PostGIS need nothing extra: their types come back as text.

## Tools

| Tool                         | What it returns                                                                                                                                                                          |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Test Connection**          | Server version, role, database, whether TLS is on and the session is read-only, and warnings about an over-privileged role. Errors say whether authentication, the network or TLS failed |
| **List Schemas**             | Schemas with their owner and number of tables and views                                                                                                                                  |
| **List Tables**              | Tables, views and materialized views with estimated row count and size on disk                                                                                                           |
| **Describe Table**           | Columns (type, nullability, default, comment), indexes, constraints, row estimate and size                                                                                               |
| **Run Query**                | Rows of one read-only `SELECT`, as objects, with `truncated` when more existed                                                                                                           |
| **Explain Query**            | The plan as JSON plus a summary; `analyze: true` adds real timings                                                                                                                       |
| **Active Queries and Locks** | Every non-idle session: query, state, wait event, runtime, blocking pids, and waiting lock requests                                                                                      |
| **Slow Queries**             | Top statements from `pg_stat_statements` by mean time, total time or calls                                                                                                               |
| **Table Stats**              | Live and dead rows, sequential vs index scans, writes, last vacuum and analyze                                                                                                           |
| **Execute Statement**        | Runs one write statement and commits it. Needs a `read_write` connection and a confirmation on every call                                                                                |

## Safety

* **Read-only by default, enforced by Postgres.** Every read tool runs in a `READ ONLY` transaction, so the server refuses a write even from a function that the statement calls. Run Query also refuses before sending anything: comments, a second statement, and write keywords such as `INSERT`, `UPDATE` or `SELECT ... INTO`.
* **Limits on every call.** `statement_timeout` defaults to 15 s (up to 55 s with `timeout_seconds`). Results stop at 500 rows (up to 5,000 with `max_rows`) and 1 MB. A cut result has `truncated: true`.
* **Writes are a separate tool.** Execute Statement only runs on a connection stored with mode `read_write`, and every call returns a `confirm_token` first that the agent must show you and send back.
* **No secrets in results.** Passwords, connection strings and keys are removed from every error message and masked in results.
* **Every call is audited.** The audit log records who called, which tool, a SHA-256 of the SQL (never the text), the row count, the duration and the outcome.

## Create a read-only role

Connect with a role that can only read. Test Connection warns when the role is a superuser or holds write privileges.

```sql theme={null}
CREATE ROLE danube_readonly LOGIN PASSWORD 'choose-a-long-password';
GRANT CONNECT ON DATABASE app TO danube_readonly;
GRANT USAGE ON SCHEMA public TO danube_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO danube_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO danube_readonly;
-- Lets Active Queries show other sessions' SQL (Postgres 10+)
GRANT pg_read_all_stats TO danube_readonly;
-- Belt and braces: every session of this role starts read-only
ALTER ROLE danube_readonly SET default_transaction_read_only = on;
```

Repeat the `GRANT USAGE` / `GRANT SELECT` lines for every schema agents should see. For **Slow Queries**, enable `pg_stat_statements`: add it to `shared_preload_libraries` and run `CREATE EXTENSION pg_stat_statements;` (RDS, Cloud SQL and Supabase expose it as a parameter or an extension toggle).

## Connect

Open **PostgreSQL** in the dashboard's tool catalog and click **Connect**, or let the agent call `store_credential`. Fill in host, port, database, user, password and SSL mode. Mode stays **Read only** unless you want Execute Statement to work.

How Danube reaches the database depends on where it lives:

<Tabs>
  <Tab title="Public endpoint">
    Managed databases with a public endpoint (Supabase, Neon, RDS with public access, Cloud SQL with a public IP) connect directly. TLS is required by default. Allow Danube's egress addresses in the database's firewall or security group: see [Connect your production database safely](/connectors/production-database#allowlist-danubes-addresses).
  </Tab>

  <Tab title="Private network, SSH bastion">
    Fill in the **SSH bastion** fields: the bastion's public host, user, private key and host key fingerprint. Set **Host** to the database's private address as the bastion sees it. Danube verifies the bastion's host key against the fingerprint you stored and never trusts a new key on first use. Leave the fingerprint empty once and Test Connection prints the key the bastion presented, so you can check it and paste it in.
  </Tab>

  <Tab title="Private network, data-plane agent">
    Run the [data-plane agent](/organizations/data-plane) inside the network and store the password as a reference, for example `env://PG_PASSWORD`. The call then runs on the agent, which resolves the reference locally. Nothing inbound is opened, and the password never reaches Danube. Build the agent image with `DANUBE_DB_ENGINES=postgres`.
  </Tab>
</Tabs>

Run **Test Connection** after saving. It tells you which of these failed: the credentials (`auth_required`), the network (`connection_error`, `destination_blocked`) or TLS (`tls_error`).

## Example prompts

* "Which tables in the `public` schema are biggest, and how many rows do they have?"
* "Find orders from the last hour with `status = 'payment_failed'` and group the errors."
* "Why is this query slow? Explain it and suggest an index."
* "Is anything blocked in the database right now?"
* "What are the ten slowest statements by mean time?"
