A read-only Postgres MCP server can still return your private customer table. In our tests, DBHub and Crystal DBA rejected writes but returned private.customers when their database login could read it. Google MCP Toolbox's generic SQL tool returned it too. Giving each server a login without access to that schema stopped the read in all three.

That makes database permissions a good place to start when choosing a Postgres MCP server. After that, decide how much freedom the agent needs: SQL it can write itself, or named queries you've already reviewed. DBHub and Toolbox supported both approaches in the configurations we tested.

Datatape publishes this comparison and sells hosted database MCP infrastructure. Datatape wasn't part of the runtime tests; these results don't rank its security or performance against the packages below.

Database grants decided private-table access

We tested DBHub 1.2.3 with readonly=true, Google MCP Toolbox 1.10.0 with postgres-execute-sql, and Crystal DBA Postgres MCP Pro 0.3.0 with --access-mode=restricted. Toolbox's generic tool had no application-level read-only setting in this configuration.

Each server used two logins in turn. One could read the allowed schema. The other had read and write grants on both allowed and private. Neither owned the tables or had superuser or BYPASSRLS privileges.

Probe against generic SQL configurationsDBHubToolboxCrystal DBA
Read the allowed Acme recordReturnedReturnedReturned
Read private.customers, restricted loginPermission deniedPermission deniedPermission denied
Read private.customers, broader loginReturnedReturnedReturned
INSERT and UPDATE, broader loginRead-only validation rejected bothBoth changed the synthetic tableSQL validation rejected both
Read another tenant's row through the fixture RLS policyNo rowsNo rowsNo rows

The private-table result is easy to miss if you only test whether the agent can change data. DBHub and Crystal DBA stopped the INSERT and UPDATE statements, yet both still allowed that read with the broader login. If customer email is outside the agent's job, rejecting writes doesn't keep it out of the response.

Toolbox's write result fits its intended use. Google describes postgres-execute-sql as a developer-assistant tool requiring human oversight and discourages its use for production agents. With the restricted login, Postgres denied both writes through that same tool.

Discovery scope did not remove access

A shorter table list can give an agent less irrelevant context. It doesn't necessarily tell you which tables the agent can query.

Both lab logins used search_path=allowed. A catalog query filtered to that search path omitted the private schema, but the broader login could still read private.customers by naming it explicitly. DBHub's search_objects also returned only allowed-schema objects in our configuration; its execute_sql tool still accepted the qualified private-table read with that login.

When checking a table allowlist, try a table that isn't in the discovery result. Postgres schema and object privileges can deny that read even if the agent knows the table's full name. The permissions tutorial shows the grants and restricted view we used.

Both DBHub and Toolbox supported a custom-only catalog

For a repeated account lookup, the agent may only need to supply a name. We configured account_by_name in DBHub and Toolbox with a fixed query and a bound $1 value. In each custom-only configuration, tools/list returned just that tool. Calling execute_sql failed because it wasn't registered.

Both servers returned Acme for the input Acme, rejected a missing name or numeric value, and returned no rows for Acme' OR '1'='1. Those results cover this query and these inputs, not every possible tool definition.

This gives you a practical choice. Keep generic SQL for work that needs exploration. For a recurring question with a known query, expose the operation directly and review changes to its SQL. A fixed query still needs appropriate database grants and caller access controls.

Predefined SQL isn't exclusive to Datatape: DBHub documents custom tools, and Toolbox documents prepared SQL tools. The Toolbox tutorial walks through our tested configuration.

Limits and error handling need their own checks

Once a query is permitted, check how much it returns and how long it can run. DBHub returned two of five rows with max_rows=2; the generic Toolbox and Crystal DBA configurations returned all five. These are configuration results, not evidence that either package lacks other ways to limit a query.

All three timed out while waiting for an exclusive table lock, then answered an ordinary read after the lock was released. DBHub used its configured timeout of about two seconds; Toolbox and Crystal DBA used the role timeout of about 1.5 seconds. The evidence records these as timeout-lock and recovery. Crystal DBA rejected the separate pg_sleep(3) probe during SQL validation, so that probe doesn't demonstrate a timeout.

Also check how your client recognizes failure. In the recorded permission, column, mutation, and timeout cases, Crystal DBA returned SQL error text with isError=false. A client relying on that field alone would miss those failures.

What we ran

The downloadable lab creates a disposable Postgres 16.10 database with synthetic records, a restricted view, and a tenant policy based on the database login. It runs on an internal Docker network, publishes no host ports, and removes its containers afterward.

The three generic configurations each ran with both logins. The DBHub and Toolbox custom-only configurations used the restricted login, for eight configurations in total. These are selected setups, not every package's default installation.

The evidence bundle includes image digests, generated configuration, tool inventories, requests, responses, and database state checks. Start with private-qualified, insert, and update to check the table above. We checked table contents before and after mutations rather than treating an empty response as proof that nothing changed.

Choose the query surface before choosing the package

DBHub lets you combine SQL exploration with configurable custom tools. Toolbox suits teams that want to define and operate named database tools themselves. Crystal DBA includes database inspection and analysis tools alongside restricted SQL execution, but its advisory needs a resolution before treating the tested release as a deployment choice.

For a recurring operational query, start with a small named-tool catalog and a login that can read only the necessary data. For exploration, give the agent SQL access within the database permissions that workflow needs. If you want a hosted option, Datatape's Postgres integration describes our approach. You'll still need to decide what the database login may access.