Step-by-step walkthrough
Control AI queries to MariaDB with GateRook’s MCP Firewall
GateRook’s MCP Firewall gives an AI app controlled access to MariaDB without putting the database password in SQL tool calls. Choose the database, expose the connection through an endpoint, and keep changes behind approval. Activity connects each request to its policy decision and execution result.
This walkthrough was performed on November 3, 2026 with GateRook 0.7.0, MariaDB 11.4.5 in Docker Desktop on macOS, and Codex already connected to the showcase development endpoint. It creates a separate mariadb-demo connection and uses four fictional orders to demonstrate discovery, reads, an approved update, and auditing. MariaDB uses GateRook's built-in MySQL connector; the connection test identifies the actual server as MariaDB.
1. Start an isolated MariaDB server
Keep Docker Desktop and GateRook running. This example assumes an existing development endpoint named showcase and an AI app connected to it. The separate container uses 127.0.0.1:13307, leaving existing database servers on other ports alone. MariaDB 11.4.5 is the exact fixture version used here, not a claim that it is the latest release.
Create a private working directory and independent passwords for the administrator and tutorial user:
mkdir -p ~/gaterook-mariadb-demo
cd ~/gaterook-mariadb-demo
umask 077
python3 - <<'PY'
from pathlib import Path
import secrets
path = Path("mariadb.env")
with path.open("x") as output:
output.write(
"MARIADB_ROOT_PASSWORD=" + secrets.token_hex(24) + "\n"
"MARIADB_DATABASE=gaterook_demo\n"
"MARIADB_USER=demo_agent\n"
"MARIADB_PASSWORD=" + secrets.token_hex(24) + "\n"
)
path.chmod(0o600)
PYCreate init.sql in the same directory:
cat > init.sql <<'SQL'
USE gaterook_demo;
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_name VARCHAR(100) NOT NULL,
status VARCHAR(20) NOT NULL,
total DECIMAL(10,2) NOT NULL,
CONSTRAINT orders_status
CHECK (status IN ('pending', 'paid', 'shipped'))
);
INSERT INTO orders VALUES
(1001, 'Avery Stone', 'pending', 129.90),
(1002, 'Morgan Reed', 'paid', 89.00),
(1003, 'Riley Chen', 'pending', 249.00),
(1004, 'Jordan Lee', 'shipped', 49.50);
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'demo_agent'@'%';
GRANT SELECT, UPDATE ON gaterook_demo.orders TO 'demo_agent'@'%';
SQLThe official image creates the database and user from the MARIADB_* variables. The initialization script then narrows that user's privileges to SELECT and UPDATE on one table. It does not grant inserts, deletes, or schema changes. These initialization settings apply to an empty data directory; changing the environment file later does not reset an existing database. See the official MariaDB image environment reference.
Start the server:
docker run -d \
--name gaterook-mariadb-showcase \
-p 127.0.0.1:13307:3306 \
--env-file mariadb.env \
--mount "type=bind,source=$(pwd)/init.sql,target=/docker-entrypoint-initdb.d/01-demo.sql,readonly" \
--health-cmd='healthcheck.sh --connect --innodb_initialized' \
--health-interval=2s \
--health-timeout=3s \
--health-retries=30 \
mariadb:11.4.5
docker inspect --format '{{.State.Health.Status}}' \
gaterook-mariadb-showcaseWait for healthy. The image's healthcheck script checks connectivity and InnoDB initialization. GateRook will separately test the tutorial user's credentials and privileges. The host port is bound only to loopback. If this container name or port is already occupied, choose another and use it consistently below.
2. Choose the MySQL connector for MariaDB
Open Connections and filter by mariadb-demo before capturing the screen. There should be no match yet. Select Add connection.

Choose MySQL, whose description explicitly includes MariaDB, then Continue. There is no separate MariaDB tile in this version. This connector supplies four SQL tools.

3. Enter the server and credentials
Use these values:
| Field | Value |
|---|---|
| Name | mariadb-demo |
| Host | 127.0.0.1 |
| Port | 13307 |
| Secret source | Encrypted here |
| User | demo_agent |
| Password | The MARIADB_PASSWORD value from your private mariadb.env |
| Environment | DEV Development |
The connection name becomes the connection argument in tool calls and the identifier used in Activity. Choose it before saving: the saved name cannot be edited because calls and policies refer to it.

Enter only the tutorial user's password value, not the MARIADB_ROOT_PASSWORD or the entire environment file. Keep it out of your AI conversation. Encrypted here stores the credential encrypted with GateRook's local master key. The connector uses it to connect; subsequent SQL calls contain a connection name, database, and statement without the password.

4. Configure encryption and the database allowlist
Expand Advanced:
| Field | Value in this walkthrough |
|---|---|
| SSL mode | Encrypt, don't verify (require) |
| CA certificate | Empty for this disposable local fixture |
| Database allowlist | Add gaterook_demo using the + button |
| Allow public key retrieval | Unchecked |
| Statement timeout | Empty: use the environment policy |
| Pool size | 2 |
| Connect timeout | 5000 ms |
| Functions reads may call | Empty |
The test container supports TLS, and the connection succeeds with encryption required. This local fixture does not verify the server certificate or host name. For a remote server, configure a trusted certificate and choose Verify the CA and host name (verify-full); add its private CA certificate when necessary. Do not turn off encryption to work around a remote certificate error.
Public key retrieval is unnecessary for this connection and remains off. MariaDB uses database names as schema names, so the allowlist contains gaterook_demo, not PostgreSQL's public.

5. Load and select the database
Select Load databases, then tick gaterook_demo. The form should show 1 databases available · 1 selected. Discovery and selection are separate: select the database you intend agents to use. Reload the list if you change the server, credentials, or connection settings.
Keep DEV Development selected. Its description says that mutations still wait for approval.

6. Test the connection
Select Continue. GateRook connects with the entered configuration and checks the user's privileges. This run returned Connected · MariaDB 11.4.5 even though the wizard uses the MySQL connector.
The detected permissions were SELECT on one table, UPDATE on gaterook_demo.orders, and no CREATE or ownership for schema changes. The write warning is expected for this demonstration. For an analytics-only connection, grant only the required read access at the database level. Approval does not give a database login privileges it lacks.

7. Add the connection to showcase
Continue to Add to endpoint. Untick default and select only showcase. The connection is not available to an AI app until an endpoint exposes it. Keep the initial modes: three Read only tools and one Approval tool.

Select Save connection. The saved page identifies MariaDB 11, reports Healthy, and shows 1 endpoint with 4 tools on showcase · Codex. The tutorial credential is stored encrypted.

Scroll to Used by and verify:
| Tool | Mode | Purpose |
|---|---|---|
sql_list_schemas | Read only | Discover databases and tables |
sql_describe_table | Read only | Inspect columns, keys, and indexes |
sql_query | Read only | Run a validated read |
sql_execute | Approval | Request a change for human review |
Keep sql_execute in Approval for this walkthrough. Bypass is a separate mode and is not used here; unused tools can be Off.

8. Understand how a call reaches MariaDB
The request path is AI app → showcase → mariadb-demo → MariaDB. The AI chooses a tool and supplies arguments. GateRook checks endpoint access, tool mode, policy, and limits; its connector uses the stored credential to contact the database, then returns the allowed result and records the call in Activity.
The connection argument is mariadb-demo. The database argument is the selected gaterook_demo; specifying it also makes the intended database clear when more than one is selected. The four tools were usable from this existing Codex session immediately after saving. If your AI app retains an older tool catalog, refresh its MCP tools or reconnect it.
Database privileges and GateRook policy are separate controls. A read-only database user cannot perform the example UPDATE even if GateRook approves it. Likewise, giving a user UPDATE permission does not bypass the endpoint's Approval mode. Returned data reaches the AI client, so scope the tables and columns it may read as well as the actions it may request.
9. Discover the table and read its rows
Ask your connected AI app:
Through showcase, use mariadb-demo and database gaterook_demo. List the tables, describe orders, show the orders sorted by id, and summarize order count and total by status.
The run used sql_list_schemas with connection: mariadb-demo and database: gaterook_demo, then sql_describe_table with those arguments plus table: orders. Discovery returned one table. Description returned four non-null columns, an integer primary key on id, and one primary index. The initializer defines a status CHECK constraint; this MariaDB description response did not list it, so an empty checks result is not evidence that the table has none.
The first sql_query used:
{
"connection": "mariadb-demo",
"database": "gaterook_demo",
"sql": "SELECT id, customer_name, status, total FROM orders ORDER BY id",
"limit": 10
}It returned four rows without truncation:
| id | customer_name | status | total |
|---|---|---|---|
| 1001 | Avery Stone | pending | 129.90 |
| 1002 | Morgan Reed | paid | 89.00 |
| 1003 | Riley Chen | pending | 249.00 |
| 1004 | Jordan Lee | shipped | 49.50 |
The second read used:
SELECT status, COUNT(*) AS order_count, SUM(total) AS total_amount
FROM orders
GROUP BY status
ORDER BY status;| status | order_count | total_amount |
|---|---|---|
| paid | 1 | 89.00 |
| pending | 2 | 378.90 |
| shipped | 1 | 49.50 |
The advertised read limit for this endpoint is 1,000 rows and five seconds; these calls request ten rows. The SQL read tool validates the statement, uses a read-only transaction, and rolls it back after reading. Send one statement per MariaDB call.
Open Activity → Agent calls and enter this filter, then press Enter:
endpoint:showcase connection:mariadb-demoOpen the grouped sql_query event. Request identifies Codex and showcase; Arguments shows the exact SQL, connection, database, and limit.

Scroll within the detail panel. Policy decision says Allowed, explaining that the read ran immediately. Result includes a three-row summary, response size and hash, and zero masked fields for this fictional dataset. Timing separates resource execution from gateway overhead.

10. Request a change and review the exact action
Ask the AI to mark order 1001 as shipped only if it is still pending. The sql_execute call uses connection: mariadb-demo, database: gaterook_demo, and this SQL:
UPDATE orders
SET status = 'shipped'
WHERE id = 1001 AND status = 'pending';GateRook returned a pending approval handle: the statement had not executed. The AI shows the approval card once and polls the same handle. It must not submit another UPDATE while waiting.

In GateRook's Approvals, inspect the connection, DEV environment, showcase endpoint, exact UPDATE, and both conditions in its WHERE clause. This request matched dev.sql.write-approval. Its impact preview identified orders, estimated 1 row using EXPLAIN, showed a transaction rolled back on error, and a 5 s statement timeout. The estimate is a preview; the execution result establishes the actual count.
A person can add an optional comment and select Approve and run, or select Deny. Opening the chat card does not approve the request. Only the person makes this decision in GateRook; an unanswered request expires at its displayed deadline. The application's protected Approvals screen was not captured; the operator's client-side cards document the pending and completed states.
In this run, the request was submitted at 11:39:22 and approved at 11:40:36 on November 3, 2026 (Europe/Madrid). Polling the original handle returned completed, committed: true, and 1 row updated.

11. Verify the saved change
Read the row again through the same endpoint and connection:
SELECT id, customer_name, status, total
FROM orders
WHERE id = 1001;The follow-up sql_query returned:
| id | customer_name | status | total |
|---|---|---|---|
| 1001 | Avery Stone | shipped | 129.90 |
This independent read verifies the database state after the approved write. It is also recorded in Activity.

12. Follow the audit trail
Return to Activity → Agent calls, keep endpoint:showcase connection:mariadb-demo, choose a time range covering the test, and select Refresh. The final view contains six calls: schema discovery, table description, the initial SELECT, the grouped SELECT, the approved UPDATE, and the verification SELECT. Five read events are Allowed; the update is Approved.

Open the sql_execute event. Arguments preserves the exact requested action, while Policy decision explains why it needed approval.

The Approval timeline records the request, desktop notification, human decision, and execution. It shows 1 min 14 s waiting and 11 ms executing, with 1 row affected. The Executed action field says that it matches the approved action byte for byte, beside the approved action's SHA-256.

The write's Result includes the committed outcome:
{
"committed": true,
"statements": [{ "type": "UPDATE", "rowsAffected": 1 }],
"rowsAffected": 1
}
Use these sections to answer: Which client used this connection? What SQL did it request? Why was it allowed or sent for approval? Who decided? Did the exact approved action run, and how many rows changed?
Result detail depends on the tool. The read events here contain compact text summaries, sizes, and hashes; Activity is not a complete archive of database results. The write event includes structured execution output. Masking depends on configured policies. Zero masked fields in these fictional records does not establish that arbitrary personal data is automatically protected. Setup changes is a separate Activity tab for changes to gateway configuration, rather than database tool calls.
Keep or stop the demo
The connection remains attached only to showcase, with reads enabled and writes requiring approval. Keep the container for further exploration. To pause access without deleting the configuration, turn the connection's On switch off; it affects this connection across endpoints. Turning an endpoint off pauses access through that endpoint. Past calls remain in Activity.
Stop the tutorial server without deleting its data:
docker stop gaterook-mariadb-showcaseResume it later:
docker start gaterook-mariadb-showcaseWait for healthy, then use Test connection in GateRook. Keep the local environment file private. For another server, update the address and database selection, use its own limited login and verified TLS configuration, and repeat the test before exposing tools.