---
title: "Ask MySQL Questions in Plain English"
description: "Ask MySQL questions in plain English: the SELECT-only user, MySQL 8 TLS auth, the server defaults that quietly change generated SQL, and reading from a replica."
canonical: https://datarelix.ai/resources/guides/ask-mysql-questions-in-plain-english/
publishDate: 2026-08-20
---

# Ask MySQL Questions in Plain English

You can **ask MySQL questions in plain English**, and the safety story is short: a MySQL user granted `SELECT` and nothing else cannot write, and every generated statement is validated again before it executes. What MySQL adds is operational — version-8 authentication wants TLS, the database is the entire scope, and a handful of server defaults quietly shape both the generated SQL and the answers it returns.

## Who this is for, and what it assumes

Engineers and analysts who run MySQL — RDS, Cloud SQL, Azure Database for MySQL, PlanetScale, or self-managed 5.7+/8.x — and are weighing whether **natural-language querying** is safe to point at it. It assumes you can run `CREATE USER` and `GRANT`. The field-by-field connection form is in the [MySQL connection guide](https://docs.datarelix.ai/guides/connections/mysql/).

## One user, one grant, one database

MySQL has no schema layer separate from the database, so the database *is* the scope — and the whole privilege model for read-only analytics fits in three statements:

```sql
CREATE USER 'datarelix_reader'@'%' IDENTIFIED BY 'choose-a-strong-password';
GRANT SELECT ON your_db.* TO 'datarelix_reader'@'%';
FLUSH PRIVILEGES;
```

The `'%'` host wildcard accepts connections from any address; tighten it to a CIDR if your server enforces host-based access control, remembering that MySQL matches *user plus host* as a pair. The full privilege model is in the [MySQL `GRANT` reference](https://dev.mysql.com/doc/refman/8.0/en/grant.html).

Prove the boundary before moving on, connected as the new user:

```sql
-- Should list exactly one privilege: SELECT ON `your_db`.*
SHOW GRANTS FOR CURRENT_USER();

-- Should fail with "command denied", which is the point:
CREATE TABLE should_not_work (id INT);
```

That grant is the boundary you own. The second one sits in front of your server regardless: a generated statement is parsed into a full syntax tree and rejected unless it is a read, so `INSERT`, `UPDATE`, `DELETE`, DDL, and MySQL-side escapes have no path through even if a privileged credential were ever supplied. The mechanism and its threat model are in [read-only AI analytics](/resources/guides/read-only-ai-analytics/).

## MySQL 8 authentication needs TLS

MySQL 8 made `caching_sha2_password` the default authentication plugin, and it refuses to send a password over an insecure channel — the error names the plugin and says *"requires secure connection"*. Managed MySQL serves TLS out of the box, so in practice this only bites self-managed servers without certificates. Connect over TLS; falling back to `mysql_native_password` works but fixes the symptom rather than the transport. One Azure note: Flexible Server takes the plain username — the `user@servername` suffix belonged to the retired Single Server and now only causes login failures.

## The SQL that comes back is MySQL's dialect, not generic

Against a fictional retailer's schema, *"How did monthly revenue develop over the last six months?"* generates something like:

```sql
SELECT
  DATE_FORMAT(o.ordered_at, '%Y-%m') AS month,
  SUM(oi.quantity * oi.unit_price) AS revenue
FROM orders AS o
JOIN order_items AS oi ON oi.order_id = o.order_id
WHERE o.status = 'completed'
  AND o.ordered_at >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH)
GROUP BY DATE_FORMAT(o.ordered_at, '%Y-%m')
ORDER BY month;
```

The markers of real MySQL: `DATE_SUB`/`CURDATE` date arithmetic, `DATE_FORMAT` for the month grain, `LIMIT` rather than `TOP` or `FETCH FIRST`, backticks only where an identifier needs them, and a `GROUP BY` that satisfies strict grouping mode. How a question becomes this query at all is covered in [text-to-SQL explained](/resources/guides/text-to-sql-explained/) — and the decisions embedded here (completed orders only, gross of refunds, calendar months) are exactly what [checking the query](/resources/guides/verify-ai-data-answers/) is for.

## Server defaults that quietly change answers

| Server reality | How it surfaces | What to know |
|---|---|---|
| **`ONLY_FULL_GROUP_BY`** — on by default since 5.7 | On servers where someone disabled it, a non-aggregated column in a grouped query returns an *arbitrary* row value — silently. | Generated SQL aggregates every selected column, which is correct on both settings. Legacy hand-written reports are where the silent version of this bug lives. |
| **`TIMESTAMP` vs `DATETIME`** | `TIMESTAMP` converts through the session time zone; `DATETIME` is stored as-is with no zone. Mixed use skews time-window answers. | Know which your schema uses before trusting an hour-grain number. |
| **`CONVERT_TZ` with named zones** | Returns `NULL` until the server's time zone tables are loaded — a classic source of suddenly-empty results. | Load them with `mysql_tzinfo_to_sql`, per [MySQL time zone support](https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html). |
| **Mixed collations** | Joining a `utf8mb3` column to a `utf8mb4` one can throw *"Illegal mix of collations"* or quietly stop using an index. | Surfaces most often on older databases upgraded in place. |
| **`lower_case_table_names`** | Table names are case-sensitive on Linux by default, case-insensitive on Windows and macOS. | A name that worked against a dev laptop can miss the table in production. Discovery surfaces names exactly as the server stores them. |
| **No `FULL OUTER JOIN`** | MySQL simply lacks it. | The generated equivalent is a `UNION` of left and right joins — more verbose, same result. |
| **MyISAM tables** | The legacy engine has no foreign-key support at all, so old tables carry no declared relationships. | Join paths get inferred from naming — see below. |

## Point it at a replica, not the primary

Analytical questions never need a write path, which makes a **read replica** the natural target: the primary keeps serving the application while ad hoc scans land elsewhere, and the reader user's grant replicates with everything else. RDS, Cloud SQL, and Azure all offer replicas as a checkbox. The one caveat is replication lag — an answer can trail the primary by seconds. For analytical questions that rarely matters; for "what is happening right now" questions, it is worth knowing which endpoint you connected.

## Connecting MySQL to Datarelix

Datarelix connects to MySQL 5.7+ and 8.x with username/password or a `mysql://` connection string; the password is stored encrypted and every other field as plain configuration. Both `mysql_native_password` and `caching_sha2_password` work. Introspection walks `INFORMATION_SCHEMA` for tables, columns, primary keys, and declared foreign keys — on Vitess-backed databases such as PlanetScale, where foreign keys are typically absent, discovery finds no declared relationships and join paths are inferred from column naming, so [check the joins on early answers](/resources/guides/verify-ai-data-answers/) and add descriptions where names are cryptic — [why semantic context matters](/resources/guides/why-semantic-context-matters/).

Every query runs under a server-side execution-time cap of 30 seconds, results are capped at 5,000 rows, and a missing `LIMIT` is appended automatically. Setup and the troubleshooting table are in the [MySQL connection guide](https://docs.datarelix.ai/guides/connections/mysql/).

## The limits on MySQL

One database per connection — cross-database joins in a single question are out, even though MySQL's SQL could address `other_db.table`. There is no write path and none is planned. The row cap makes bulk export the wrong tool. And answer quality follows schema quality: a well-named schema with declared keys answers well; a legacy schema of cryptic columns, MyISAM tables, and undocumented status codes yields fluent SQL against the wrong column until you curate descriptions.

## Provenance

Privilege behavior follows the [MySQL `GRANT` reference](https://dev.mysql.com/doc/refman/8.0/en/grant.html); authentication-plugin behavior follows [caching_sha2_password documentation](https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html); time-zone behavior follows [MySQL time zone support](https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html). Product statements describe Datarelix as shipped in August 2026 and are stated canonically on the [security page](/security/). The SQL example uses a fictional demo schema and is illustrative, not captured output.

## Create the reader and re-ask a number you already trust

Run the three-statement grant above — against a replica if you have one — then follow the [quickstart](https://docs.datarelix.ai/quickstart/) and ask a question your existing reporting already answers. Compare the generated SQL's definitions to the report's before comparing the numbers. Your first 14 days run at Pro limits, no credit card required.
