Docs · DBCatz

Production safety

The three DBCatz safety modes, which statements ask first or are refused, and the checks that run before a structure change.

A database client should make the scary things hard to do by accident. In DBCatz every connection has a safety mode, every statement is sorted into read, write or destructive before it runs, and structure changes are checked against the table first. Curiosity is fine; dropping production on a Friday is not.

The three safety modes

Choose the mode under Safety in the connection form:

Mode In the form What it does
Normal Edit freely; risky changes still ask. Reads and writes run. Destructive statements ask with one click.
Production Asks before every write; marked PROD. Every write asks. Destructive statements need the connection’s name typed. A PROD badge on the tab and in the sidebar.
Read-only Only reads; the server session is read-only too. Every write is refused before it is sent. A READ-ONLY badge on the tab and in the sidebar.

DevCatz services are always Normal.

What asks first in the Query tab

Before a statement runs, DBCatz sorts it:

Normal Production Read-only
Read (SELECT, SHOW, GET …) Runs Runs Runs
Write (INSERT, UPDATE … WHERE, most ALTER …) Runs Asks: Write to <name>? (one click) Refused
Destructive (list below) Asks: Run this? (one click) Asks: Destructive on <name>? — type the connection’s name Refused

A refused statement never reaches the server: Read-only connection: this statement changes data or structure.

The dialog (Ask before a write) shows a title, what will happen, the statements themselves and — when a word is needed — Type <word> to go ahead.

Edits in the grid and the JSON editor

Saving a cell, inserting or deleting rows, and saving a JSON value are writes too. On a Production connection each one asks with one click (<action> on <name>?). On Read-only the grid is not editable at all.

What counts as destructive

SQL (MySQL, MariaDB, PostgreSQL, SQLite)

  • DROP … (table, database, index, view …)
  • TRUNCATE
  • UPDATE or DELETE without a WHERE
  • ALTER … DROP …
  • ALTER that changes a column’s type (MODIFY, CHANGE, ALTER COLUMN … TYPE)
  • RENAME
  • GRANT / REVOKE
  • SET GLOBAL / SET PERSIST
  • FLUSH, RESET, PURGE, KILL, SHUTDOWN

Any other ALTER — adding a column or an index, say — is a plain write: it runs on Normal and asks with one click on Production.

A few statements that look like reads count as writes: SELECT … INTO OUTFILE, SELECT … FOR UPDATE, EXPLAIN ANALYZE (it really runs the statement) and a PRAGMA with =.

Redis and Valkey

FLUSHALL, FLUSHDB, CONFIG, SHUTDOWN, DEBUG, MIGRATE, REPLICAOF / SLAVEOF, SWAPDB, MOVE, RESTORE, SCRIPT, FUNCTION and ACL.

MongoDB

drop(), deleteMany({}) and updateMany({}) with an empty filter, and the commands drop, dropDatabase and dropIndexes. An aggregate with $out or $merge counts as a write.

Elasticsearch

Any DELETE request, and _delete_by_query.

The second lock on Read-only connections

For MySQL, MariaDB and PostgreSQL, a Read-only connection also opens the server session read-only, so even a statement DBCatz misjudged would be stopped by the server:

Engine Session setting
MySQL / MariaDB SET SESSION TRANSACTION READ ONLY
PostgreSQL default_transaction_read_only=on

SQLite, Redis / Valkey, MongoDB and Elasticsearch have no such session switch. There DBCatz refuses writes itself — once in the window, and again in the app’s main process before anything is sent.

Checks before a structure change

Changing a column, adding an index or dropping one goes through a check of the table first. Each finding has a level:

Level What happens
Blocked It cannot be done from here: Can’t <action> from here, with the reason and what to do instead.
Risk You type the name to go ahead.
Note One click.

What DBCatz checks for:

  • dropping or changing the primary key, a primary key that would allow NULL, auto increment turned off;
  • foreign keys — types, character set and collation must match the referenced column; columns another table points at; an index a foreign key needs;
  • dropping the last column of a table;
  • existing values that would not fit — longer than the new length, not numbers, with decimals for an integer type, not in the new ENUM list, or NULLs in a column that becomes NOT NULL;
  • duplicates before a UNIQUE, and UNIQUE on a new NOT NULL column;
  • type and collation changes, and text turned into another type;
  • building an index on a large table, and a large table rebuild;
  • renaming — Apps using the old name break;
  • dropping an index — Queries may get slower.

The main process checks again before the ALTER is sent, so the window cannot skip it.

Dropping and emptying

Action What you confirm
Drop one table Drop ? — type the table’s name.
Truncate one table Empty ? — type its name, then Delete all rows.
Drop or truncate several tables Type the database’s name — or, on Production, the connection’s name.
Drop a database Drop database — type its name.
Flush keys (Redis / Valkey) Flush keys — type the database’s name.

Dropping or truncating a single table that other tables reference is refused (Other tables reference it). For several tables at once there is a Force option — see Bulk actions.

AI and safety

Nothing an AI feature suggests runs without your click, and every suggestion goes through the same checks as a query you typed. On a Read-only connection, changes are dropped from Ask DBCatz answers and refused again if they reach Run.

When a write is refused

That is the point of the mode. Confirm it in the dialog, or — if the connection really is not production — switch it to Normal with Edit… in its row menu.

Last updated 2026-10-30