> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oleria.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL

> Connect self-managed or cloud-managed MySQL and MariaDB so Oleria can discover accounts, roles, grants, and access paths across your databases.

Connect MySQL or MariaDB to Oleria to see every account, role, and privilege grant across your databases, and who can reach what data. Oleria also flags risky configuration, such as accounts without a password, administrators reachable from any host without TLS, and accounts that can impersonate any other account.

> [!NOTE]
>
> This integration supports self-managed MySQL 8, Percona Server 8, and MariaDB 10.4 or later, Google Cloud SQL for MySQL, Amazon RDS for MySQL and MariaDB, Aurora MySQL 3, and Azure Database for MySQL Flexible Server. Pick the setup path that matches your deployment below.

## What Oleria discovers

| Area | Detail |
| :- | :- |
| **Accounts** | Every account that can sign in, identified as `user@host`. The same user name from two hosts is two accounts, and anonymous accounts are included. MySQL has no email field, so Oleria synthesizes one for identity matching, except where the user name or the cloud identity is already an email address. |
| **Service accounts** | Accounts Oleria classifies as non-human identities: replication-only accounts, Google Cloud SQL IAM service accounts, and any account that matches the **Service Account Patterns** you set. Provider-managed accounts, such as `rdsadmin`, `azure_superuser`, and Cloud SQL `root@localhost`, appear as system accounts. |
| **Roles and groups** | MySQL and MariaDB roles, role memberships, default roles, and mandatory roles. MySQL has no groups, so the only groups are LDAP group mappings. |
| **Resources** | The server, databases, tables, views, routines, triggers, and events, plus columns that have a column grant. System schemas (`mysql`, `sys`, `information_schema`, `performance_schema`) are not shown as resources. |
| **Access grants** | Global, database, table, column, and routine grants, with MySQL's own privilege names. Partial revokes appear as denials. Accounts with `SUPER` or full control get access to every database. |
| **Impersonation** | `PROXY` grants, accounts that can create objects with another account as `DEFINER` (`SET_ANY_DEFINER`, `SUPER`), existing `DEFINER` views, routines, triggers, and events, `CREATE USER`, writes to the `mysql` schema, and LDAP proxy mappings. |
| **Credentials** | A password credential for each account that has a password stored in MySQL. Oleria records whether it is expired or locked, never the password or its hash. |
| **Risk signals** | Anonymous account, account without a password, administrator reachable from any host without TLS, global `ALL PRIVILEGES` or `SUPER`, privileges granted `WITH GRANT OPTION`, can impersonate any account, `PROXY` privilege granted, `DEFINER` object whose definer doesn't exist, password expired, password never expires, legacy authentication plugin, and remote account without a TLS requirement. |
| **Activity** | Logins (successful and failed), logouts, schema changes, grants and revokes, role and account changes, and denied statements, read from your server's audit log. Requires an audit log configured for your deployment - see setup below. |

## Prerequisites

* A MySQL or MariaDB account with permission to create users and grant privileges, to create the account Oleria uses.
* A network path from Oleria to your database on its port (default `3306`). Google Cloud SQL is the exception: Oleria connects through the Cloud SQL connector, so you don't need to open a network path. Servers on a private network that Oleria can't reach aren't supported yet.
* Cloud-provider credentials matching your deployment - see [Set up the integration](#set-up-the-integration) below.
* Optional: extra privileges on the same account, if you also want to run remediation actions. See [Remediation actions](#remediation-actions).

> [!NOTE]
>
> Oleria reads accounts and grants from the `mysql` system schema, so its account needs `SELECT` on `mysql.*`. That also lets the account read password hashes. Oleria never reads them, but MySQL has no narrower grant that shows other accounts' privileges. Never share this account with a person: on the cloud deployments, Oleria excludes its own activity by account name alone.

> [!WARNING]
>
> MySQL silently hides databases, views, and routines from an account that lacks the privileges below, so a connection without them would sync a partial picture. To prevent that, Oleria refuses the connection and names the missing privilege. Oleria checks the privileges again on every sync.

## Set up the integration

Create a dedicated account for Oleria on every deployment. Run this as an administrator (`root`, or your cloud provider's admin or master user):

```sql theme={null}
CREATE USER 'oleria_reader'@'%' IDENTIFIED BY '<strong password>' REQUIRE SSL;
GRANT SELECT ON mysql.* TO 'oleria_reader'@'%';
GRANT SHOW DATABASES, SHOW VIEW, PROCESS ON *.* TO 'oleria_reader'@'%';
GRANT SHOW_ROUTINE ON *.* TO 'oleria_reader'@'%';
```

* `SELECT ON mysql.*` shows accounts, grants, and roles.
* `SHOW DATABASES` and `SHOW VIEW` are required, and so is `SHOW_ROUTINE` on MySQL 8.0.20 and later.
* `PROCESS` is recommended. It lets Oleria see sessions and tell its own session apart. Without it the connection works, but **Disable user accounts** can't end sessions.
* On MariaDB, leave out `SHOW_ROUTINE`, which doesn't exist there. `SELECT` on `mysql.*` already covers routines, so you don't need global `SELECT`. On MySQL before 8.0.20, which also has no `SHOW_ROUTINE`, routines and definer impersonation are skipped with a warning unless the account has global `SELECT`.

These grants are optional:

```sql theme={null}
GRANT TRIGGER, EVENT ON *.* TO 'oleria_reader'@'%';
GRANT REPLICATION CLIENT ON *.* TO 'oleria_reader'@'%';
```

* `TRIGGER` and `EVENT` let Oleria see trigger and event definers. Without them, triggers and events are skipped. Both privileges can also change data, so grant them only if you want that coverage.
* `REPLICATION CLIENT` lets Oleria label replication topology.

> [!NOTE]
>
> If you give these privileges through a role, make it a default role of the account, or turn on `activate_all_roles_on_login`. Otherwise MySQL doesn't apply them when Oleria connects.

> [tab] Self-managed
>
> **1. Create the account**
>
> Run the statements above as `root`. Oleria recommends TLS, so make sure your server has a certificate. If you set **TLS Mode** to **Disabled (not recommended)**, create the account without `REQUIRE SSL`, because the server refuses a plain connection for that account.
>
> **2. Enable an audit log for activity (optional)**
>
> Oleria reads activity over the same connection, and uses the first of these your server offers:
>
> 1. **MySQL Enterprise Audit or Percona's audit log filter,** with the log format set to JSON (the `audit_log_format` or `audit_log_filter.format` setting, depending on your product and version). Oleria reads it with `audit_log_read()`. The format is set at startup. A newly installed audit plugin logs nothing until you assign a filter, so also run:
>
> ```sql theme={null}
> SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }');
> SELECT audit_log_filter_set_user('%', 'log_all');
> ```
>
> 2. **The general query log as a table.** Run `SET GLOBAL log_output = 'TABLE'; SET GLOBAL general_log = 'ON';`, and set the same values in your configuration file so they survive a restart. This works on MySQL, Percona, and MariaDB.
>
> > [!WARNING]
> >
> > The general log records every statement, so it grows quickly. It also has no success or failure flag, so Oleria can't show failed logins or denied statements from it. Use an audit plugin if you can. Without either option, Oleria connects but shows no activity.
>
> > [!NOTE]
> >
> > MySQL's documentation doesn't say which privilege `audit_log_read()` needs. If activity doesn't appear on MySQL Enterprise, check whether the account also needs `AUDIT_ADMIN`.

> [tab] Google Cloud SQL
>
> **1. Create the account**
>
> Connect as `root`, which holds `cloudsqlsuperuser`, and run the statements above, but leave `REQUIRE SSL` out of the `CREATE USER` statement. The Cloud SQL connector encrypts the connection itself, and a Cloud SQL instance can enforce encryption for all connections with its own **SSL mode** setting.
>
> **2. Create a service account**
>
> 1. In **IAM & Admin**, create a service account.
>
> 2. Grant it **Cloud SQL Client** (`roles/cloudsql.client`) on the project that contains the instance.
>
> 3. To show activity, also grant it **Private Logs Viewer** (`roles/logging.privateLogViewer`). Cloud SQL audit entries are Data Access audit logs, which only that role can read.
>
> 4. Create a JSON key for the service account and download it. You paste the entire file into Oleria.
>
> **3. Note your Cloud SQL connection name**
>
> On the instance's **Overview** page, copy the **Connection name** in `project:region:instance` format. Oleria connects through the Cloud SQL connector, so you don't need to allowlist IP addresses. The connector uses the instance's public IP, so an instance that has only a private IP can't connect.
>
> **4. Use IAM database authentication instead of a password (optional)**
>
> To avoid storing a database password, set the `cloudsql_iam_authentication` database flag to **On**, and grant the service account **Cloud SQL Instance User** (`roles/cloudsql.instanceUser`) as well. Then add the service account as an IAM database user:
>
> ```bash theme={null}
> gcloud sql users create <service-account-email> --instance=<instance> --type=cloud_iam_service_account
> ```
>
> The new user has no privileges, so grant it the same privileges as above. The MySQL user name is the service account's email without the `@<project>.iam.gserviceaccount.com` suffix. When you connect, choose **Cloud SQL IAM authentication**.
>
> **5. Turn on the audit plugin for activity (optional)**
>
> 1. Set the `cloudsql_mysql_audit` database flag to `ON`. This restarts the instance, and `gcloud sql instances patch --database-flags` replaces the whole flag list, so pass every existing flag along with the new one.
>
> 2. In **IAM & Admin** -> **Audit Logs**, find **Cloud SQL API** and enable the **Data Read** and **Data Write** log types. Data Access audit logs are off by default, and without them Cloud SQL writes no audit entries Oleria can read.
>
> 3. Create an audit rule. The plugin records only activity that matches a rule. To audit everything, run this as an administrator:
>
> ```sql theme={null}
> CALL mysql.cloudsql_create_audit_rule('*', '*', '*', '*', 'B', 1, @outval, @outmsg);
> SELECT @outval, @outmsg;
> ```
>
> The fifth argument, `B`, records both successful and unsuccessful operations, so Oleria sees failed logins and denied statements.
>
> > [!NOTE]
> >
> > Auditing covers the primary instance only, not replicas. Audit rules are stored in the database, so restoring a backup rolls them back to that point in time.

> [tab] Amazon RDS / Aurora
>
> **1. Create the account**
>
> Connect as the master user and run the statements above. Oleria always connects over TLS and verifies the server certificate against the Amazon RDS certificate authority.
>
> **2. Use IAM database authentication instead of a password (optional)**
>
> To avoid storing a database password, enable **IAM database authentication** on the instance or cluster. Then create the account with the AWS authentication plugin instead of a password:
>
> ```sql theme={null}
> CREATE USER 'oleria_reader'@'%' IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS' REQUIRE SSL;
> ```
>
> Grant it the same privileges as above. When you connect, choose **AWS IAM database authentication** as the authentication type.
>
> **3. Create the Oleria access role with CloudFormation**
>
> Oleria never uses its own AWS credentials in your account. Instead, you create a read-only IAM role from a CloudFormation template that only Oleria can assume, and only with an external ID unique to this connection. You launch the template while you connect - see [Connect MySQL to Oleria](#connect-mysql-to-oleria).
>
> The role allows:
>
> | Permission | Used for |
> | :- | :- |
> | `logs:FilterLogEvents` on `/aws/rds/*` log groups | Reading the audit log for activity. |
> | `logs:DescribeLogGroups` | Finding how far back the audit log goes. |
> | `rds:DescribeDBInstances`, `rds:DescribeDBClusters`, `rds:DescribeDBClusterEndpoints` | Finding the instance or cluster behind your endpoint. |
> | `rds-db:connect` | Used only with IAM database authentication. |
>
> **4. Turn on auditing and CloudWatch Logs export for activity (optional)**
>
> Oleria reads activity from the audit log RDS exports to CloudWatch Logs.
>
> * **RDS for MySQL and MariaDB:** In an option group, add the **MARIADB\_AUDIT\_PLUGIN** option and set `SERVER_AUDIT_EVENTS` to `CONNECT,QUERY`. Attach the option group to the instance. Then, on the instance, go to **Modify** -> **Log exports** and enable **Audit log**.
>
> * **Aurora MySQL:** In the DB cluster parameter group, set `server_audit_logging` to `ON` and `server_audit_events` to `CONNECT,QUERY`. The first time you attach the parameter group, restart the cluster. Then, on the cluster, go to **Modify** -> **Log exports** and enable **Audit log**.
>
> > [!NOTE]
> >
> > Use the `QUERY` class rather than only `QUERY_DDL`, `QUERY_DML`, and `QUERY_DCL`. With the narrower classes, `ALTER USER` (lock, unlock, and password changes) isn't logged. Optionally add `rdsadmin` to `SERVER_AUDIT_EXCL_USERS` (`server_audit_excl_users` on Aurora) to cut noise from RDS health checks. Oleria already ignores that account.

> [tab] Azure Flexible Server
>
> **1. Create the account**
>
> Connect as the server's administrator login and run the statements above.
>
> **2. Use Microsoft Entra authentication instead of a password (optional)**
>
> To sign in without a database password, enable Microsoft Entra authentication on the server (Azure also needs a user-assigned managed identity that can read your directory), set a Microsoft Entra administrator, and register an application in **Microsoft Entra ID** with a client secret (**Certificates & secrets** -> **New client secret**). As the Microsoft Entra administrator, create a MySQL user for the application, and grant it the privileges above. When you connect, choose **Microsoft Entra authentication** and enter the user name of that MySQL user.
>
> **3. Turn on audit logs for activity (optional)**
>
> 1. Under **Settings** -> **Server parameters**, set `audit_log_enabled` to **ON**, and set `audit_log_events` to `CONNECTION_V2,GENERAL`. `CONNECTION_V2` records whether each login succeeded. `GENERAL` records data, schema, permission, and administrative statements.
>
> 2. Under **Monitoring** -> **Diagnostic settings**, add a diagnostic setting, select the **MySqlAuditLogs** category, choose **Send to Log Analytics workspace**, and pick your workspace.
>
> > [!WARNING]
> >
> > Oleria reads the `AzureDiagnostics` table. If Azure asks for a destination table, choose **Azure diagnostics**. If the logs go to a resource-specific table instead, the connection syncs normally but shows no activity, with nothing indicating why.
>
> 3. In the Log Analytics workspace, open **Access control (IAM)** and assign the application you registered the **Log Analytics Reader** role.
>
> **4. Note your server and workspace details**
>
> Collect the Flexible Server name (the part before `.mysql.database.azure.com`), your Microsoft Entra tenant ID, the application's client ID and secret, and the Log Analytics Workspace ID - the workspace's ID (a GUID) from its **Overview** page, not its resource ID.

## Connect MySQL to Oleria

**1. Open the integration**

Sign in to your Oleria workspace and navigate to **Integrations** -> **MySQL** -> **Connect**.

**2. Complete the connection form**

Select your **Deployment** first. The form updates to show only the fields that deployment needs.

> [tab] Self-managed
>
> | Field | Notes |
> | :- | :- |
> | **Deployment** | Select **Self-managed (VM or on-premises)**. |
> | **Host** | Required. The hostname or IP address of your server, reachable from Oleria. |
> | **Port** | Defaults to `3306`. |
> | **User** | Required. The account you created above. |
> | **Password** | Required. |
> | **TLS Mode** | **Verify CA and host name** (default), **Verify CA**, **Encrypt without verifying the certificate**, or **Disabled (not recommended)**. Use the last two only for a server you control, such as one with a self-signed certificate. |
> | **CA Certificate (optional)** | The PEM certificate of the private CA that signed your server certificate. When you give one, it is the only certificate Oleria trusts. |

> [tab] Google Cloud SQL
>
> | Field | Notes |
> | :- | :- |
> | **Deployment** | Select **Google Cloud SQL for MySQL**. |
> | **Cloud SQL Connection Name** | Required. In `project:region:instance` format. |
> | **GCP Service Account Key (JSON)** | Required. The entire JSON key file for the service account you created above. Oleria has no default Google credentials to fall back on. |
> | **Authentication** | **Password** (default) or **Cloud SQL IAM authentication**. |
> | **User** | Required. The account you created above. For IAM authentication, the database user of the IAM principal. |
> | **Password** | Required for password authentication. |

> [tab] Amazon RDS / Aurora
>
> | Field | Notes |
> | :- | :- |
> | **Deployment** | Select **Amazon RDS or Aurora (MySQL or MariaDB)**. |
> | **Host** | Required. The instance or cluster endpoint from the RDS console. Oleria works out the region, instance, and audit log group from it. |
> | **Port** | Defaults to `3306`. |
> | **Authentication** | **Password** (default) or **AWS IAM database authentication**. |
> | **User** | Required. The account you created above. |
> | **Password** | Required for password authentication. |
>
> After you select **Authenticate**, Oleria shows a second step to create the access role:
>
> 1. Open the CloudFormation link Oleria provides. It opens the AWS console with the template and an external ID already filled in. Create the stack in your AWS account.
>
> 2. When the stack finishes, open its **Outputs** tab and copy the role ARN.
>
> 3. Back in Oleria, paste it into **Role ARN**, select **Confirm that the role is created using CloudFormation successfully**, and select **Authenticate**.
>
> > [!WARNING]
> >
> > The external ID changes every time you submit the first step. Create the stack once, and don't submit the first step again afterward. If you do, update the stack's `ExternalId` parameter to the value in the newest link, or delete the stack and create it again.
>
> > [!NOTE]
> >
> > Deleting the integration in Oleria doesn't delete the CloudFormation stack or its role, because they belong to your AWS account. Delete the stack yourself.

> [tab] Azure Flexible Server
>
> | Field | Notes |
> | :- | :- |
> | **Deployment** | Select **Azure Database for MySQL (Flexible Server)**. |
> | **Azure Server Name** | Required. The server name, for example `myserver`. Oleria builds the host as `myserver.mysql.database.azure.com`. |
> | **Authentication** | **Password** (default) or **Microsoft Entra authentication**. |
> | **User** | Required. The account you created above. For Microsoft Entra authentication, the Microsoft Entra user or group name. |
> | **Password** | Required for password authentication. |
> | **Log Analytics Workspace ID (optional)** | The workspace that receives the server's audit logs. Leave blank to skip activity. |
> | **Azure Tenant ID**, **Azure Client ID**, **Azure Client Secret** | Required for Microsoft Entra authentication, and when you enter a workspace ID. Use the application you registered above. |

On every deployment, turn on **Advanced settings** to set two optional fields:

| Field | Notes |
| :- | :- |
| **Service Account Patterns (optional)** | Comma-separated `LIKE` patterns for accounts Oleria should classify as service accounts, for example `svc_%,etl_%@10.%`. A pattern with `@` is matched against `user@host`. |
| **Protected Accounts (optional)** | Comma-separated `user@host` accounts that Oleria actions must never change, in addition to the built-in and administrator accounts. |

**3. Complete the connection**

Select **Authenticate**. Oleria validates the connection and its privileges, discovers your accounts, roles, resources, and access, and begins the first sync.

## Verify the integration

Confirm MySQL appears on the **Connected** tab of your Oleria **Integrations** page. After the first sync completes, you can review the discovered accounts, roles, resources, access grants, and activity in your Oleria workspace.

If the connection is refused with an error that names a missing privilege, grant it to the account and try again.

## Remediation actions

Oleria runs remediation actions with the same account it syncs with, so grant that account the extra privileges below if you want to use them. The **Capabilities** tab on the integration's page shows which actions are available, and which need a privilege.

| Action | What it does | Privileges the account needs |
| :- | :- | :- |
| **Add user to role** | Runs `GRANT role TO user@host`. Reversible. | `SELECT` on `mysql.*`, and `ROLE_ADMIN`. On MariaDB, `WITH ADMIN OPTION` on the role instead. |
| **Remove user from role** | Runs `REVOKE role FROM user@host`. Reversible: the undo grants the role back with its original admin option. | The same as **Add user to role**. |
| **Disable user accounts** | Locks the account with `ALTER USER ... ACCOUNT LOCK`, then ends its open sessions. Reversible. Requires approval in Oleria. | `SELECT` on `mysql.*`, `CREATE USER`, `PROCESS`, and a way to end sessions: `CONNECTION_ADMIN` (on MariaDB 10.5.2 and later, `CONNECTION ADMIN` with a space), or on Amazon RDS `EXECUTE` on `mysql.rds_kill`, or on Azure `EXECUTE` on `mysql.az_kill`. |
| **Enable user accounts** | Unlocks the account with `ALTER USER ... ACCOUNT UNLOCK`. Reversible. | `SELECT` on `mysql.*` and `CREATE USER`. |
| **Disable NHI accounts** | Does the same as **Disable user accounts**, for a service account. Requires approval in Oleria. | The same as **Disable user accounts**. |
| **Revoke permission to resource instance** | Runs `REVOKE` for the privileges you select on a database, table, column, routine, or the server. Reversible: the undo grants back exactly what it revoked. | `SELECT` on `mysql.*`, and each privilege you revoke held `WITH GRANT OPTION` at that scope. For example, to revoke `SELECT` on the `sales` database, the account needs `GRANT SELECT ON sales.* TO 'oleria_reader'@'%' WITH GRANT OPTION`. Grant this only for the scopes you want to revoke, because `GRANT OPTION` lets the account pass those privileges on to others. |

> [!NOTE]
>
> Without a way to end sessions, **Disable user accounts** still locks the account, but sessions that are already open stay open until they end. On Amazon RDS and Azure, the administrator can't grant `CONNECTION_ADMIN`, so grant `EXECUTE` on the kill procedure instead.

> [!NOTE]
>
> Every action reads before it writes. If the account is already in the target state, Oleria changes nothing, and its undo changes nothing either. Oleria never changes its own account, provider-managed accounts, administrator accounts, anything in **Protected Accounts**, or mandatory roles, and it refuses a target that matches more than one account.

## Known limitations

* **No creation date or last sign-in:** MySQL stores neither, so Oleria shows dormancy only from activity in the audit log.
* **No account creation or deletion:** Oleria locks and unlocks accounts, changes role membership, and revokes privileges. It can't create or delete an account or grant a privilege.
* **Groups:** MySQL has no groups. Oleria shows LDAP group mappings, and group membership comes from your directory integrations.
* **Cloud administrators aren't visible over SQL:** People who can reset the administrator password through your cloud provider (for example, `cloudsql.users.update` on Google Cloud, `rds:ModifyDBInstance` on AWS, or the Contributor role on Azure), and anyone with operating system access, don't appear in the database. Oleria models them on the instance.
* **Statement text is redacted:** Oleria replaces literal values, long numbers, emails, and comments in audited statements with `<redacted>`, and keeps the statement's shape.
* **Self-managed activity:** A self-managed server with no audit plugin, no general log table, and no JSON audit log shows no activity. A MariaDB audit plugin that writes only to a file isn't read.
* **Activity history:** Oleria backfills about six months, but each source holds only what its retention keeps: since you turned on export for RDS and Aurora (unless you set a log group retention), 30 days by default on Google Cloud SQL and Azure, and what is still on disk or in the log table for self-managed servers. Oleria can't show events older than that.
* **Activity gaps by source:** Google Cloud SQL doesn't list role grants or revokes among the operations its audit plugin logs. On Azure, `CONNECTION_V2` records the result of each login. Without it, a refused login looks like a successful one. The general log has no success or failure flag.
* **Private networks:** Oleria can't reach a server that is only on a private network. Google Cloud SQL connects through the Cloud SQL connector, which uses the instance's public IP.

## Contact us

For questions about this integration, contact us at [support@oleria.com](mailto:support@oleria.com).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.