MySQL

MySQL Audit Logging: MariaDB Audit Plugin, General Log, and Trigger-Based Auditing

Implement MySQL audit logging for SOC2, PCI-DSS, and HIPAA compliance. Covers MariaDB Audit Plugin, general query log, trigger-based auditing, and SIEM integration.

JusDB Team
Published April 16, 2025
Updated August 1, 2026
7 min read

A production MySQL audit trail needs a supported event source, explicit coverage rules, protected storage, and recurring tests that prove events still arrive. The correct mechanism depends on the product and hosting model: MySQL Enterprise Audit, the MariaDB Audit Plugin, and Amazon RDS for MySQL's managed audit option are related in purpose but are not interchangeable installation paths. Audit data can support an investigation or control assessment; enabling a plugin alone does not guarantee compliance.

Choose the Audit Mechanism for the Platform

PlatformSupported starting pointImportant boundary
Oracle MySQL Enterprise EditionMySQL Enterprise Audit, implemented by the audit_log server pluginIt is a commercial Enterprise Edition component. Use the installation procedure shipped for the exact MySQL release.
MariaDB ServerMariaDB Community Audit Plugin, named server_auditIt is a MariaDB plugin with its own event types, variables, file or syslog output, and version matrix.
Amazon RDS for MySQLThe managed MARIADB_AUDIT_PLUGIN option in a custom RDS option groupAttach the provider option; there is no host access for copying a plugin or installing a CloudWatch agent.
Oracle MySQL Community Edition on a self-managed hostEvaluate a supported vendor or service-specific audit componentMySQL Enterprise Audit is not a Community Edition feature. Do not assume a MariaDB binary is supported on a current Oracle MySQL release.

The general query log records client connections, disconnects, and statements received by the server, but MySQL disables it by default and documents it primarily as a diagnostic facility. Its volume, broad statement capture, limited policy controls, and sensitive contents make it a poor substitute for a designed security audit trail. If it is enabled for a short investigation, set the output deliberately, protect the destination, measure overhead, and define when it will be disabled.

Define Coverage Before Filters

Start with the questions the trail must answer: which authenticated account connected, whether authentication succeeded, which administrative or data operation occurred, which database object was involved, when the server observed it, and whether the event reached protected storage. Map those questions to supported event classes on the chosen platform. Include changes to accounts, privileges, audit configuration, schemas, and high-risk data paths where the product can observe them. Record the database's authenticated identity as well as application identity in a separate, trustworthy application field when a shared connection pool would otherwise hide the end user.

Avoid excluding replication, monitoring, or administrative accounts merely to reduce noise. A privileged account can also be the account whose use most needs review. First measure its events, document why each event class is or is not required, and use a narrow filter only after security and operations owners approve the gap. Amazon RDS documents a possible exclusion for its internal rdsadmin activity because it can be frequent, but that provider-specific exception is not a reason to exclude customer-controlled privileged users. On RDS, CONNECT activity remains recorded for all users even when an exclusion list is configured.

Configure MySQL Enterprise Audit Deliberately

Modern MySQL Enterprise Audit uses JSON rule-based filters stored in audit tables and assigned to accounts with functions such as audit_log_filter_set_filter() and audit_log_filter_set_user(). Install both the plugin and its supporting tables and functions according to the exact 8.4 documentation; otherwise the plugin can fall back to deprecated legacy filtering. Rule-based filtering initially logs no events until a filter is assigned. A default assignment to % covers accounts without an explicit filter, while an account-specific assignment affects new connections. Treat a filter change like a security policy deployment: review the JSON, canary it, reconnect test accounts, and inspect the resulting records.

Restrict AUDIT_ADMIN, monitor audit configuration changes, and consider a startup activation mode that prevents casual unloading where operationally appropriate. MySQL warns that audit files are unencrypted by default and may contain SQL text. Store them in a directory readable only by the server and authorized reviewers; where the Enterprise feature and keyring design support it, evaluate audit-log encryption. Rotate without creating collection gaps, forward copies to a separately administered destination, and alert on missing files, stalled ingestion, unexpected volume drops, parsing failures, and retention failures. An administrator who can change filters and erase every copy does not face a tamper-resistant control.

Configure MariaDB and RDS as Separate Cases

On MariaDB Server, verify that server_audit is present in the configured plugin directory, load it using MariaDB's documented plugin mechanism, select event classes, enable logging, and configure rotation or syslog output. Confirm information_schema.PLUGINS reports the expected active plugin after every restart. MariaDB's option names and event semantics belong to MariaDB; do not paste them into a MySQL Enterprise Audit configuration.

For Amazon RDS for MySQL, add MARIADB_AUDIT_PLUGIN to a custom option group that matches the DB engine and major version, configure its supported SERVER_AUDIT_* settings, and associate that group with the instance. To publish the managed audit log to CloudWatch Logs, enable the audit log export on the DB instance. AWS requires the audit option and file log output for publication; RDS then creates database log streams. Do not deploy a CloudWatch agent configuration that points at /var/log/mysql: customers cannot read an RDS host filesystem.

aws rds modify-db-instance \
  --db-instance-identifier mydbinstance \
  --cloudwatch-logs-export-configuration '{"EnableLogTypes":["audit"]}'

After the change, generate a canary event and find that exact event in the RDS audit log and CloudWatch destination. An accepted API change is not proof that audit records are complete. Apply least privilege to CloudWatch access, set retention intentionally, protect downstream archives from routine database administrators, and test what happens when forwarding permissions or quotas fail.

Use Triggers Only for Business Change History

A trigger-maintained history table can preserve useful before-and-after values for selected row changes. It is an application data feature, not comprehensive database auditing. A table trigger does not observe logins, failed authentication, reads, many administrative statements, privilege changes, operations on other tables, or actions taken after the trigger is disabled. Its audit insert normally shares the business transaction, so a rollback also rolls back that history row. A sufficiently privileged user may modify the trigger and its destination.

Use triggers when the product needs a domain history such as an order status transition, and store the authenticated application actor through a controlled session context rather than trusting arbitrary client text. Restrict writes to the history table, monitor trigger definitions, and reconcile the history with server or provider audit events. Never describe a trigger table as independently tamper-resistant evidence.

Validate Coverage and Operability

  1. Inventory controls. Record engine, edition, exact version, plugin or option version, filter revision, destination, retention, encryption, owners, and approved exclusions.
  2. Run a canary matrix. From named test identities, exercise successful and failed connections, a read, write, DDL change, privilege change, denied statement, and audit-policy change where those events are in scope.
  3. Trace the whole path. Match server time, connection identity, event identifier, and statement category in the local or managed log, collector, central store, search index, and alert.
  4. Test failure modes. Exercise rotation, restart, destination unavailability, malformed records, clock drift, collector restart, and a deliberate configuration mismatch in a safe environment.
  5. Measure impact. Load-test representative traffic with the selected event classes and output strategy. Compare latency, throughput, storage growth, and log-delivery delay before rollout.
  6. Review evidence. Reconcile expected canaries with received events, investigate gaps, review exclusions and privileged access, and repeat after engine upgrades or filter changes.

Compliance frameworks impose different scoping, retention, access-review, and evidence requirements. Have the responsible security or compliance owner map this tested trail to the actual control language. For adjacent controls, see the MySQL least-privilege permissions guide and the Performance Schema operations guide.

Official Primary Documentation

Operational Takeaways

  • Select the audit component supported by the exact database product and hosting model.
  • Approve exclusions only after measuring their security coverage, not simply to reduce volume.
  • Keep an independently protected copy and alert on audit gaps as well as suspicious events.
  • Use triggers for selected business history, never as a comprehensive audit substitute.
  • Prove the full event path with repeatable canaries; plugin-enabled is not the same as evidence-complete.

Share this article

JusDB Team

Official JusDB content team

Keep reading

MySQL Explained (2026): InnoDB, 8.4 LTS, Replication & Production Patterns

Everything you need to know about MySQL: storage engines, replication topologies, performance tuning, and cloud deployment. From basics to advanced optimization.

MySQL9 minMay 13, 2026
Read

MySQL binlog Retention, Rotation & Purge: Production Guide (2026)

Configure MySQL binlog retention safely: binlog_expire_logs_seconds, manual purging rules, AWS RDS retention, and the disk-exhaustion failure mode you should monitor for.

MySQL10 minMay 9, 2026
Read

MySQL "Communications Link Failure": Fix wait_timeout, HikariCP & All 8 Timeout Variables

MySQL wait_timeout, net_read_timeout, innodb_lock_wait_timeout and max_execution_time — production tuning rules and the HikariCP alignment trick that prevents 'communications link failure' errors.

MySQL6 minMay 9, 2026
Read