> ## Documentation Index
> Fetch the complete documentation index at: https://agno-v2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Database

> Route SQL database reads and writes through separate SQLAlchemy engines.

**DatabaseContextProvider** routes database reads and writes through separate SQLAlchemy engines. It exposes `query_database` for reads and `update_database` for writes.

## Prerequisites

```shell theme={null}
uv pip install -U agno sqlalchemy openai
# Plus your database driver:
uv pip install -U psycopg2-binary  # PostgreSQL
uv pip install -U pymysql          # MySQL
```

```bash Mac/Linux theme={null}
export OPENAI_API_KEY="your_openai_api_key_here"
```

```bash Windows theme={null}
$Env:OPENAI_API_KEY="your_openai_api_key_here"
```

## Example

```python theme={null}
import asyncio

from sqlalchemy import create_engine

from agno.agent import Agent
from agno.context.database import DatabaseContextProvider
from agno.models.openai import OpenAIResponses

# Database roles enforce permissions for each engine.
readonly_engine = create_engine("postgresql://reader:pass@localhost/mydb")
sql_engine = create_engine("postgresql://writer:pass@localhost/mydb")

db = DatabaseContextProvider(
    sql_engine=sql_engine,
    readonly_engine=readonly_engine,
    schema="public",
)

agent = Agent(
    model=OpenAIResponses(id="gpt-5.4"),
    tools=db.get_tools(),
    instructions=db.instructions(),
)


async def main() -> None:
    await agent.aprint_response("How many orders were placed last month?")


if __name__ == "__main__":
    asyncio.run(main())
```

> [!WARNING]
>
> **Both engines are required.** The provider routes read requests to `readonly_engine` and write requests to `sql_engine`. Configure `readonly_engine` with database credentials restricted to SELECT operations and the allowed schemas. The `schema` parameter controls table discovery, not authorization for arbitrary SQL.

## Provider Params

| Parameter | Type | Default | Description |
| - | - | - | - |
| `sql_engine` | `Engine` | required | SQLAlchemy engine used by the write sub-agent. Its database credentials determine write permissions. |
| `readonly_engine` | `Engine` | required | SQLAlchemy engine used by the read sub-agent. Use SELECT-only credentials restricted to the allowed schemas. |
| `schema` | `str \| None` | `None` | Schema used when listing tables and describing columns. It does not authorize or restrict arbitrary SQL. |
| `id` | `str` | `"database"` | Provider ID. Tools become `query_<id>` and `update_<id>`. |
| `name` | `str \| None` | `None` | Display name. Defaults to `id` ("database"). |
| `read_instructions` | `str \| None` | `None` | Custom instructions for the read sub-agent. |
| `write_instructions` | `str \| None` | `None` | Custom instructions for the write sub-agent. |
| `mode` | `ContextMode` | `default` | Tool exposure mode. See [Architecture](https://agno-v2.mintlify.site/context-providers/overview.md#mode). |
| `model` | `Model \| None` | `None` | Model for the sub-agents. Defaults to Agno's default model. |
| `read` | `bool` | `True` | Expose `query_database` tool. |
| `write` | `bool` | `True` | Expose `update_database` tool. |

## Tools Exposed

| Tool | Description |
| - | - |
| `query_database` | Answer database questions through the read sub-agent and `readonly_engine`. |
| `update_database` | Apply database changes through the write sub-agent and `sql_engine`. |

## Privilege Separation

The read and write sub-agents use separate database connections:

```
query_database  → readonly_engine → read replica / SELECT-only user
update_database → sql_engine      → writable connection
```

The separate engines route each tool to the intended connection. Database roles enforce the boundary. Grant the reader role SELECT-only access to the required schemas, and grant the writer role only the write permissions it needs. The `schema` parameter helps the agent discover tables and columns but does not block cross-schema SQL.

## Multiple Databases

Use different `id` values to expose multiple databases:

```python theme={null}
orders_db = DatabaseContextProvider(
    id="orders",
    sql_engine=orders_write_engine,
    readonly_engine=orders_read_engine,
)

inventory_db = DatabaseContextProvider(
    id="inventory",
    sql_engine=inventory_write_engine,
    readonly_engine=inventory_read_engine,
)

agent = Agent(
    model=...,
    tools=[*orders_db.get_tools(), *inventory_db.get_tools()],
)
# Agent sees: query_orders, update_orders, query_inventory, update_inventory
```

## Read-only Tool Surface

```python theme={null}
db = DatabaseContextProvider(
    sql_engine=engine,
    readonly_engine=readonly_engine,
    write=False,
)
# Agent only sees query_database
```

`write=False` removes `update_database` from the agent's tools. It does not change the permissions of `readonly_engine`, so keep that engine restricted at the database level.

## Cookbook

> **[Database Context Provider](https://github.com/agno-agi/agno/blob/main/cookbook/12_context/04_database_read_write.py)**
>
> Read/write with separate engines


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.