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

# Safe data access

> Enforce read and write boundaries with database permissions and transaction settings.

Enforce read-only access with database roles and grants. Use a separate connection with schema-scoped permissions for approved write operations. These controls remain in effect when model output is unexpected.

```bash theme={null}
uv pip install "agno[openai,psycopg,sql]"
```

```python theme={null}
from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.tools.sql import SQLTools
from sqlalchemy import create_engine

readonly_engine = create_engine(
    "postgresql+psycopg://readonly@warehouse/analytics",
    connect_args={"options": "-c default_transaction_read_only=on"},
)

analyst = Agent(
    name="Analyst",
    model=OpenAIResponses(id="gpt-5.5"),
    tools=[SQLTools(db_engine=readonly_engine)],
    instructions="Answer questions from the public schema. You cannot write.",
)
```

Create the `readonly` role without write grants before using this connection. The `default_transaction_read_only=on` setting blocks ordinary write statements. This setting is a configurable session default. Database ownership and grants remain the security boundary.

## Split the roles

Most data-agent questions are read-only. Separate approved writes, such as building a summary table or recording a correction, into agents with dedicated connections.

| Member       | Connection                                            | Can do                                | Cannot do           |
| ------------ | ----------------------------------------------------- | ------------------------------------- | ------------------- |
| **Analyst**  | Read-only role on `public`                            | Introspect, SELECT, answer            | Any write, anywhere |
| **Engineer** | Read on `public`, read-write on an agent-owned schema | Build views in its own schema         | Touch `public`      |
| **Leader**   | No direct database access                             | Route the request, compose the answer | Run SQL itself      |

The Engineer's writes are scoped to a schema (for example `dash`) that the Analyst never touches. The database rejects `DROP TABLE public.users` because the Engineer's role has no write grant on `public`.

## Gate the writes that remain

For writes you do allow, add a human in the loop. `requires_confirmation` produces a paused run that the client must continue with an approval before the function executes.

```python theme={null}
from agno.tools import tool


@tool(requires_confirmation=True)
def materialize_view(name: str, sql: str) -> str:
    """Create a view in the agent-owned schema after human approval."""
    ...
```

For a dedicated writer built on `SQLTools`, set `requires_confirmation_tools=["run_sql_query"]`. This pauses every call to the tool, including reads. A narrow custom write tool gives finer control. Gate irreversible actions and leave reads ungated so approval fatigue does not set in.

## Layers of defense

| Layer                | Enforced by                                                                    |
| -------------------- | ------------------------------------------------------------------------------ |
| Read-only answers    | Database role with no write grant                                              |
| Write isolation      | Schema-scoped grant on a separate connection                                   |
| Irreversible actions | Human approval via `requires_confirmation`                                     |
| Auditability         | The [Decision Log](/learning/stores/decision-log) records what changed and why |

## Next steps

| Task                                  | Guide                                                     |
| ------------------------------------- | --------------------------------------------------------- |
| Let the Engineer build reusable views | [Materialization](/use-cases/data-agents/materialization) |
| Approve sensitive actions             | [Human approval](/hitl/overview)                          |

## Developer Resources

* [Human approval](/hitl/overview)
* [Dash: dual-schema enforcement](/deploy/templates/dash/overview)
