Skip to content

Rate this page
Thanks for your feedback
Thank you! The feedback has been submitted.

For help, click the link below to get free database assistance or contact our experts for personalized support.

Migrate to the audit log filter component

Percona Server for MySQL 8.4 replaces two legacy audit sources — the audit_log plugin and the transitional audit_log_filter plugin — with component_audit_log_filter. This page covers migration from either source: it maps plugin configuration to the component’s system variables and filter JSON, and walks through a safe cutover.

Before you start, read:

Note

The component and the plugin use different system variables and a different on-disk format. Do not enable both at the same time, and do not set audit_log_* plugin variables on a server running the component. See the deprecation notice on the plugin page.

Which source are you migrating from?

Two legacy sources exist. The target is the same (component_audit_log_filter), but the starting point differs:

Source Recommended path
audit_log plugin (pre-8.4 installs, still available in 8.4 as a deprecated plugin) Upgrade to 8.4, install the component, translate audit_log_* variables to filter JSON, validate in parallel, then uninstall the plugin.
audit_log_filter plugin (transitional, 8.0 and early 8.4 builds) Upgrade to 8.4 first, then transition to the component per Upgrade from plugins to components → Transition after upgrade.

The detailed mapping below targets the audit_log plugin, because its configuration model (global audit_log_* variables and policy presets) differs most from the component. If you are migrating from the audit_log_filter plugin, the filter JSON you already wrote continues to work unchanged; your migration reduces to a shorter path:

  1. Upgrade the server to 8.4.
  2. Uninstall the plugin.
  3. Run the component install script (see Install the audit log filter) — this creates mysql.audit_log_filter and mysql.audit_log_user and registers the component.
  4. Re-apply each filter with audit_log_filter_set_filter() and re-assign accounts with audit_log_filter_set_user(). If you exported the plugin’s filter/user tables, those rows can be re-inserted directly.
  5. Move non-filter settings (file path, format, rotation, syslog) from audit_log_filter_* plugin variables to the audit_log_filter.* component variables listed in the variable mapping below.

See also Upgrade from plugins to components → Transition after upgrade.

What changes, at a glance

  • Configuration moves from global audit_log_* system variables into JSON filter definitions stored in mysql.audit_log_filter, plus per-account assignments in mysql.audit_log_user.
  • Scope moves from a single global include/exclude list to per-account assignments — admin@% and app@% can use different filters on the same server.
  • Rule changes no longer require a restart or plugin reinstall: update the JSON with audit_log_filter_set_filter() and the next session picks it up.
  • Log format names shift: the plugin’s OLD / NEW / JSON / CSV become the component’s OLD / NEW / JSON / JSONL. There is no CSV output in the component.
  • The audit_log_handler = SYSLOG path becomes audit_log_filter.handler = SYSLOG with the same syslog sub-variables renamed.

Migration steps

  1. Inventory the current configuration. On the 8.0 (or plugin-enabled 8.4) server, capture the legacy settings:
SHOW VARIABLES LIKE 'audit_log_%';

Save the output. You will translate each non-default value into either a component variable, a filter JSON rule, or a audit_log_filter_set_user() call.

  1. Upgrade the server to 8.4 following Upgrade procedures. The audit_log plugin remains loadable in 8.4 so that the old log keeps flowing during the transition.

  2. Install the component per Install the audit log filter. The install script creates mysql.audit_log_filter and mysql.audit_log_user, then runs INSTALL COMPONENT.

  3. Translate configuration using the two mapping tables below. Apply non-filter settings (file path, format, rotation, syslog) as component variables; apply scope settings (policy, include/exclude lists) as a filter definition plus user assignments.

  4. Run in parallel (optional, recommended). With both the plugin and the component loaded, verify that events you care about appear in the component’s log. Compare record types, SQL text, and redactions.

  5. Cut over. Uninstall the plugin (UNINSTALL PLUGIN audit_log;), remove audit_log_* entries from my.cnf, and leave the component as the sole audit writer. If you also had the transitional audit_log_filter plugin loaded, uninstall it as well.

  6. Verify. Log in as a subject account, execute a representative statement, and read the new log with audit_log_read() or by opening the file.

Option and variable mapping

The following maps plugin system variables (left) to component system variables (right). Anything not listed has no direct equivalent because it is subsumed by the filter JSON grammar.

Plugin variable Component equivalent Notes
audit_log_file audit_log_filter.file Default file name and data-directory placement differ; see Log file naming.
audit_log_format (OLD/NEW/JSON/CSV) audit_log_filter.format (OLD/NEW/JSON/JSONL) CSV is not supported by the component. For line-delimited ingest, use JSONL (see JSON and JSONL).
audit_log_strategy audit_log_filter.strategy Same ASYNCHRONOUS / PERFORMANCE / SEMISYNCHRONOUS / SYNCHRONOUS trade-offs.
audit_log_buffer_size audit_log_filter.buffer_size Applies to ASYNCHRONOUS / PERFORMANCE.
audit_log_rotate_on_size audit_log_filter.rotate_on_size Size-based rotation.
audit_log_rotations audit_log_filter.prune_seconds + audit_log_filter.max_size The component prunes by age and total size instead of a fixed file count. Convert “keep N files” to an age or total-size budget.
audit_log_flush audit_log_rotate() Manual rotation is now a UDF call rather than a variable toggle.
audit_log_handler (FILE / SYSLOG) audit_log_filter.handler Same two values.
audit_log_syslog_ident audit_log_filter.syslog_tag Renamed.
audit_log_syslog_facility audit_log_filter.syslog_facility
audit_log_syslog_priority audit_log_filter.syslog_priority
audit_log_policy (filter JSON) Translate to class selection — see below.
audit_log_include_accounts / audit_log_exclude_accounts (filter JSON + audit_log_filter_set_user()) Per-account assignment replaces global lists — see below.
audit_log_include_commands / audit_log_exclude_commands (filter JSON) Use log conditions that test general_sql_command.str.
audit_log_include_databases / audit_log_exclude_databases (filter JSON) Use log conditions that test table_database.str in table_access.

Component-only features that have no plugin counterpart include block-on-match (abort), field redaction (print / replace), predefined variables and functions inside conditions, and dynamic filter swapping (activate / ref). See Write filter definitions and its sub-pages.

Translating audit_log_policy to filter JSON

audit_log_policy gated what the plugin recorded. The component expresses the same four choices as filter definitions:

Plugin policy Equivalent filter definition
ALL Log everything the component sees (respects audit_log_filter.event_mode): { "filter": { "log": true } }
LOGINS { "filter": { "class": { "name": "connection" } } }
QUERIES { "filter": { "class": [ { "name": "general" }, { "name": "table_access" } ] } }
NONE Either do not assign a filter to the account, or bind an empty filter: { "filter": {} }

Install any of these with audit_log_filter_set_filter() and assign them with audit_log_filter_set_user(). For example:

SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }');
SELECT audit_log_filter_set_user('%',        'log_all');

Translating include/exclude lists

The plugin filtered globally. The component filters per account (via audit_log_user) and per event (via log conditions that compare event fields). Most migrations combine both.

Accounts

Plugin:

SET GLOBAL audit_log_include_accounts = 'app@%,admin@localhost';

Component — assign a logging filter to the two accounts and leave the default % with no filter (or an empty filter):

SELECT audit_log_filter_set_filter('log_all', '{ "filter": { "log": true } }');
SELECT audit_log_filter_set_user('app@%',          'log_all');
SELECT audit_log_filter_set_user('admin@localhost','log_all');

Plugin exclude list, inverted:

SET GLOBAL audit_log_exclude_accounts = 'monitor@%';

Component — keep the default % assigned to a logging filter and assign monitor@% to an empty filter (or leave it unassigned if % has no filter):

SELECT audit_log_filter_set_filter('no_log', '{ "filter": {} }');
SELECT audit_log_filter_set_user('monitor@%', 'no_log');

Commands

Plugin:

SET GLOBAL audit_log_include_commands = 'select,insert,update,delete';

Component — narrow the general class with a log condition that tests general_sql_command.str:

SELECT audit_log_filter_set_filter('log_dml', '{
  "filter": {
    "class": {
      "name": "general",
      "log": {
        "field": {
          "name": "general_sql_command.str",
          "value": ["select", "insert", "update", "delete"]
        }
      }
    }
  }
}');

For exclusion, wrap the condition in not.

Databases

Plugin:

SET GLOBAL audit_log_include_databases = 'app,reports';

Component — narrow table_access by table_database.str:

SELECT audit_log_filter_set_filter('log_app_reports', '{
  "filter": {
    "class": {
      "name": "table_access",
      "log": {
        "field": {
          "name": "table_database.str",
          "value": ["app", "reports"]
        }
      }
    }
  }
}');

For a complete grammar reference (field names, logical operators, variables, functions), see Write filter definitions and Definition fields reference.

Worked example

Starting plugin configuration in my.cnf:

[mysqld]
plugin-load-add          = audit_log.so
audit_log_format         = JSON
audit_log_policy         = ALL
audit_log_include_accounts = app@%,admin@localhost
audit_log_exclude_commands = set_option
audit_log_rotate_on_size = 104857600
audit_log_rotations      = 10

After upgrading to 8.4 and running audit_log_filter_linux_install.sql, replace it with:

[mysqld]
audit_log_filter.format         = JSON
audit_log_filter.rotate_on_size = 104857600
audit_log_filter.prune_seconds  = 2592000

Then define the filter and assign accounts:

SELECT audit_log_filter_set_filter('log_all_except_set_option', '{
  "filter": {
    "class": [
      { "name": "connection" },
      { "name": "table_access" },
      {
        "name": "general",
        "log": {
          "not": {
            "field": { "name": "general_sql_command.str", "value": "set_option" }
          }
        }
      }
    ]
  }
}');

SELECT audit_log_filter_set_user('app@%',           'log_all_except_set_option');
SELECT audit_log_filter_set_user('admin@localhost', 'log_all_except_set_option');

Accounts that do not match app@% or admin@localhost — and that have no explicit assignment to the default % filter — are not audited, which reproduces the plugin’s include-list behavior.

Cutover and verification

  1. Confirm the component is live:

    SELECT * FROM mysql.component WHERE component_urn = 'file://component_audit_log_filter';
    
  2. Log in as a subject account, run a representative statement, and read the new log:

    SELECT audit_log_read('{}');
    

    See Read log files.

  3. Uninstall the legacy plugin and clear its settings from my.cnf:

    UNINSTALL PLUGIN audit_log;
    
  4. Rotate once so new writes go to a fresh file under the component’s naming scheme:

    SELECT audit_log_rotate();
    
  5. For any pre-existing plugin log files you want to keep, archive them. The component does not ingest them, but you can run filter_audit_log_filter_files to post-process component logs.

Known caveats

  • Log content changes slightly even when you keep the same format. Some statements that the 8.0 plugin did not record now appear in 8.4 logs because the server sends additional events (the plugin page calls out the SELECT $$ example). Percona does not plan to backport format changes to match 8.0 output.
  • The component stores state in mysql.audit_log_filter and mysql.audit_log_user. Back up those tables before making bulk changes, and include them in your normal mysql database backups.
  • Lifecycle events (server_startup, server_shutdown, and the audit class itself) are not valid filter targets — see Definition fields reference.
  • audit_log_filter.event_mode defaults to REDUCED. If you relied on plugin logging for classes beyond connection, general, table_access, and message, set event_mode = FULL to match the broader class set.

Additional reading