connect a database
Connect MySQL or MariaDB
Provisioning read-only credentials for MySQL or MariaDB — the same instructions Evalyst shows you when a credential check fails.
Run as a user that holds CREATE USER and GRANT OPTION (usually root on the primary; grants
replicate to the rest of the cluster).
-- 1. the account. Scope the host as tightly as you can — the app's egress IP, or the subnet
-- your bastion/proxy connects from, not '%'.
CREATE USER 'evalyst_reader'@'<app_ip_or_subnet>' IDENTIFIED BY '<STRONG_PASSWORD>';
-- 2. SELECT on exactly one schema. Nothing else — no INSERT/UPDATE/DELETE, no DDL,
-- no FILE (that is `SELECT … INTO OUTFILE` / `LOAD_FILE`), no SUPER, no GRANT OPTION.
GRANT SELECT ON `<your_db>`.* TO 'evalyst_reader'@'<app_ip_or_subnet>';
-- 3. optional but recommended: cap what one session can burn
ALTER USER 'evalyst_reader'@'<app_ip_or_subnet>'
WITH MAX_USER_CONNECTIONS 8 MAX_QUERIES_PER_HOUR 20000;
FLUSH PRIVILEGES;
Deliberately not granted: CREATE TEMPORARY TABLES. Evalyst never needs it, and its absence
is one more thing standing between a bug and your data.
Check it yourself
mysql -u evalyst_reader -p'<PW>' -h <host> -e "SELECT COUNT(*) FROM <your_db>.<table>;" # works
mysql -u evalyst_reader -p'<PW>' -h <host> -e "DELETE FROM <your_db>.<table> LIMIT 1;" # must FAIL
mysql -u evalyst_reader -p'<PW>' -h <host> -e "SHOW GRANTS;" # SELECT only
Notes
- How Evalyst verifies this without writing anything. It runs
UPDATE \evalyst_readonly_probe` SET x = 1 WHERE 1 = 0against a table that does not exist. MySQL checks table privileges *before* table existence, so error 1142 (command denied) proves the account cannot write, while 1146 (no such table`) proves it can — the privilege check passed and only the table was missing. Nothing is created or modified either way. - Point at a replica if you have one.
@@global.read_onlyis reported in the verify evidence. - ProxySQL / connection proxies. The user must exist in two places: the backend cluster
(
CREATE USER+GRANT) and the proxy’s own user table. See your platform team’s runbook for the ProxySQL steps. - Connecting over SSH. For a database on a private network, give Evalyst a bastion instead of
opening port 3306:
config.ssh = {"host": "<bastion>", "user": "<ssh user>", "key_secret_ref": "SSH_PRIVATE_KEY"}, and keepconfig.hostas the address the bastion uses (commonly127.0.0.1, when MySQL listens on the db host’s loopback). Host-key trust is per-source, not from~/.ssh/known_hosts— see the bastion notes. - Statement timeout. The driver sets
max_execution_timeper session from the source’scost_caps.statement_timeout_ms. This only boundsSELECT, which is all Evalyst runs.