Guide · 02
Access modes and guardrails
What your assistant can do in read, write and admin mode, and what NexQL refuses no matter which mode you pick.
Every connection has an access mode. It’s the main switch for what the assistant may do, and it’s checked on every call, by nexql-mcp and, in read mode, by Postgres too.
The three modes
| Mode | What it allows | How to turn it on |
|---|---|---|
read (default) |
Look at the schema and run SELECT / WITH queries. |
Nothing to do. |
write |
Also INSERT, UPDATE, DELETE through execute_sql, edit_row and import_data. |
--access-mode write, access_mode = "write" in a profile, or the “Allow changes to data” switch in Claude Desktop. |
admin |
Also schema changes and server operations: apply_ddl, create_index_concurrently, run_maintenance, terminate_query. |
--access-mode admin or access_mode = "admin". |
Write and admin tools aren’t even listed to the assistant until at least one connection allows them. After raising a profile’s mode, restart your app so it sees the new tools.
Asking the assistant to raise a profile’s mode through save_profile needs confirm_elevated_access: true on the call, so it can’t happen as a side effect.
Superusers are kept read-only
If the connection logs in as a database superuser, nexql-mcp warns you, and write or admin mode is quietly turned back to read-only unless you start it with --i-know-what-im-doing. The assistant is told why, so it can tell you.
A superuser can read files on the database server and run programs there. A prompt-injected query could misuse that. Connect as a role with only the rights it needs instead. This prints the SQL for a least-privilege read role:
npx -y nexql-mcp@latest profile readonly-role
CREATE ROLE nexql_readonly WITH LOGIN PASSWORD 'replace-with-a-secret';
GRANT pg_read_all_data TO nexql_readonly;
Blocked in every mode
Some things are refused whatever the access mode, because they reach outside the database or hide what a query really does:
- Reading or listing server files:
pg_read_file,pg_read_binary_file,pg_ls_*,pg_stat_file, large-object functions (lo_*). - Reaching other servers:
dblink*. - Running SQL hidden in a string, which would skip every other check:
query_to_xmland its siblings. - Changing session settings (
set_config) and stalling the server (pg_sleep). CREATE DATABASEandDROP DATABASE. NexQL works on objects inside a database, never on the list of databases.
Outside admin mode, COPY to or from a file or program and pg_cancel_backend / pg_terminate_backend are refused too.
Checks on writes
- One statement per call, parsed by Postgres’s own parser.
- Transactions.
execute_sql,edit_row,import_dataandapply_ddlrun inside a transaction. An error rolls everything back. - Dry runs.
dry_run: trueruns the change, shows before-and-after snapshots of the affected rows, then rolls back. - Destructive DDL asks you. For a CRITICAL-risk statement such as
DROP TABLEorTRUNCATE,apply_ddlasks you directly in your app when it supports MCP elicitation. Otherwise the call needsconfirm_destructive: true. The assistant is told not to set that on its own. - Lock warnings.
check_ddl_safetyflags changes that would lock or rewrite a table and suggests the safer form.
Limits on every query
| Limit | Default | Change it with |
|---|---|---|
| Rows returned | 50 per call, up to 500 | max_rows in a profile, or --max-rows (1 to 10,000) |
| Statement timeout | 30 seconds | statement_timeout_ms in a profile. A call can lower it. |
| Raised timeout for bulk writes | up to 10 minutes | NEXQL_MCP_MAX_TIMEOUT_MS |
| Result size | 20,000 characters | Results are cut, with a note saying so. |
Narrowing what’s visible
In a profile:
schemas = ["public", "billing"] # only these schemas
deny_schemas = ["audit"] # never these
deny_tables = ["auth.*", "public.api_keys"]
Denied tables don’t appear in searches, and queries that touch them are refused. In Claude Desktop, the install form’s schema list sets schemas. On the command line it’s --schemas public,billing.
--tools (see Tool sets) controls how many tools the assistant sees. It’s a context-size setting, not a security boundary: access mode is what decides what runs.