> ## Documentation Index
> Fetch the complete documentation index at: https://ngquct-docs-fix-500-query-results.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Safe Mode

> Per-connection query execution controls, from no restrictions to full read-only lockdown

Six levels, one per connection, set in the **Customization** pane of its edit form. The level decides what stands between a query and the server: nothing, a confirmation, Touch ID, or a refusal.

## Levels

| Level                | Write queries           | Read queries            | Authentication      |
| -------------------- | ----------------------- | ----------------------- | ------------------- |
| **Silent**           | Execute immediately     | Execute immediately     | None                |
| **Alert**            | Confirmation dialog     | Execute immediately     | None                |
| **Alert (Full)**     | Confirmation dialog     | Confirmation dialog     | None                |
| **Safe Mode**        | Confirmation + Touch ID | Execute immediately     | Touch ID / password |
| **Safe Mode (Full)** | Confirmation + Touch ID | Confirmation + Touch ID | Touch ID / password |
| **Read-Only**        | Blocked entirely        | Execute immediately     | None                |

New connections start at **Silent**, which is the right choice for a local database you own. Move a shared staging connection to **Alert** and anything with real customer data in it to **Safe Mode** or **Read-Only**.

Four things the table cannot carry. The confirmation dialog previews the SQL it is about to run. Touch ID falls back to your macOS password on a Mac without it. **Silent** is not a free pass: `DROP`, `TRUNCATE`, and a `DELETE` with no `WHERE` still raise the built-in dangerous query warning even there. And **Read-Only** goes past queries to the interface itself, disabling inline cell editing, adding, deleting and duplicating rows, table truncate and drop, and import.

## What the level gates

Safe Mode sits in front of query execution, saving cell edits, structure and table changes, sidebar operations, imports, and maintenance jobs, including the ones the [AI assistant](/features/ai-assistant) and the MCP tools ask for.

It does not sit in front of reading metadata. Loading the sidebar, opening a table's structure, and exporting data are never confirmed, which is why a backup stays available on a Read-Only connection.

## Drivers without read-only support

The Redis, MongoDB, and etcd drivers cannot open a read-only session, so Safe Mode treats every query on those connections as a write: the Alert and Safe Mode levels confirm everything, and Read-Only blocks everything. Every other driver classifies reads and writes normally.

## Toolbar badge

The level appears as a badge in the toolbar, orange for the Alert levels and red for Safe Mode and Read-Only. Click it to change level.

<Frame caption="Safe Mode badge in the toolbar">
  <img className="block dark:hidden" src="https://mintcdn.com/ngquct-docs-fix-500-query-results/HJY892UtvXUv1PFn/images/safe-mode-toolbar-badge.png?fit=max&auto=format&n=HJY892UtvXUv1PFn&q=85&s=7058844595e38018c26bcca16d294e5b" alt="Safe Mode level badge and picker in the toolbar" width="1560" height="960" data-path="images/safe-mode-toolbar-badge.png" />

  <img className="hidden dark:block" src="https://mintcdn.com/ngquct-docs-fix-500-query-results/HJY892UtvXUv1PFn/images/safe-mode-toolbar-badge-dark.png?fit=max&auto=format&n=HJY892UtvXUv1PFn&q=85&s=feecf777c0f5d474639c939abda68790" alt="Safe Mode level badge and picker in the toolbar" width="1560" height="960" data-path="images/safe-mode-toolbar-badge-dark.png" />
</Frame>

There is no session-only override. A change from the badge writes back to the saved connection, so it holds across tables and tabs, shows up in the Customization pane, and reaches your other Macs when iCloud Sync is on. Editing the level in the form works the same way round and reaches an open connection right away.

## Server read-only is not Safe Mode

Safe Mode runs inside TablePro. It cannot make a server accept a write the server itself refuses, and the wording tells you which one refused. "Cannot execute write queries: TablePro's Safe Mode is set to read-only for this connection" is the app. Anything else is the server, and the usual causes are these:

* You are connected to a read replica or a reader endpoint rather than the primary.
* The server runs with `read_only` or `super_read_only` turned on.
* The server or the session opens new transactions read-only.

TablePro opens its write transactions as read-write, so a server that only defaults new transactions to read-only accepts the save anyway. On MySQL and MariaDB this narrows down the rest:

```sql theme={null}
SHOW SESSION VARIABLES WHERE Variable_name IN
  ('transaction_read_only', 'tx_read_only', 'read_only', 'super_read_only', 'innodb_read_only');
```

`innodb_read_only` set to `ON` means you are on a replica. Connect to the primary to write.

## Execution log

TablePro records each authorization decision, allowed or refused, to a local log: the time, the connection, the kind of operation, whether it was a write, and the outcome. The statement is stored as a SHA-256 digest, so the log is not a second copy of your data. Each record carries the hash of the one before it, so recomputing the chain shows whether a record was edited, reordered or removed.

<Warning>
  This is tamper evident, not tamper proof. Anyone who can write the file can recompute every hash after the record they changed, and truncating the end leaves a chain that still verifies. Only storing it somewhere the audited person cannot write would fix that.
</Warning>

The log is local. It is not synced and not sent anywhere.

## Managed by an organization

An administrator can impose a minimum level through a macOS configuration profile, delivered by an MDM such as Jamf or Kandji. The profile targets the `com.TablePro` preference domain with one flat key:

| Key                                        | Type   | Value                                                                     |
| ------------------------------------------ | ------ | ------------------------------------------------------------------------- |
| `com.TablePro.policy.minimumSafeModeLevel` | String | `silent`, `alert`, `alertFull`, `safeMode`, `safeModeFull`, or `readOnly` |

A connection set below the floor is raised to it, and a stricter choice is left alone: the policy is a floor, never a ceiling. A value TablePro does not recognize imposes no floor at all. While the policy is in force the matching control appears dimmed.

This is a floor on TablePro's own behavior, not on the database. It stops the app issuing a write; it does not stop the same person connecting with `psql`. Pair it with server-side privileges for anything that has to hold.

## External clients

A write from an external client (Raycast, Cursor, Claude Desktop, any MCP client) clears three locks in order:

1. **External Clients** (per connection: **Blocked** / **Read Only** / **Read & Write**), in the connection form's **Advanced** pane. A Read Only connection rejects a write before the request reaches the database.
2. **Token scope** (per integration: `readOnly` / `readWrite` / `fullAccess`), issued by the [pairing flow](/external-api/pairing). The effective permission is `MIN(token.scope, connection.externalAccess)`.
3. **Safe Mode**, per query. Everything on this page then applies, Touch ID prompts and confirmation dialogs included.

`DROP` and `TRUNCATE` always go through the `confirm_destructive_operation` tool, which needs a `fullAccess` token and the user's approval every time: through the client's own elicitation prompt where it has one, otherwise through TablePro's dialog. No token scope skips it. See the [External API security model](/external-api/index#security-model).
