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:
- Upgrade from plugins to components — timing, general procedure, and which plugins transition before vs. after the server upgrade.
- Audit Log Filter overview — what the component is and why it replaces the plugin.
- Install the audit log filter — install script, component URN, and the
mysql.audit_log_filter/mysql.audit_log_usertables.
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:
- Upgrade the server to 8.4.
- Uninstall the plugin.
- Run the component install script (see Install the audit log filter) — this creates
mysql.audit_log_filterandmysql.audit_log_userand registers the component. - Re-apply each filter with
audit_log_filter_set_filter()and re-assign accounts withaudit_log_filter_set_user(). If you exported the plugin’s filter/user tables, those rows can be re-inserted directly. - Move non-filter settings (file path, format, rotation, syslog) from
audit_log_filter_*plugin variables to theaudit_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 inmysql.audit_log_filter, plus per-account assignments inmysql.audit_log_user. - Scope moves from a single global include/exclude list to per-account assignments —
admin@%andapp@%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/CSVbecome the component’sOLD/NEW/JSON/JSONL. There is noCSVoutput in the component. - The
audit_log_handler = SYSLOGpath becomesaudit_log_filter.handler = SYSLOGwith the same syslog sub-variables renamed.
Migration steps¶
- 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.
-
Upgrade the server to 8.4 following Upgrade procedures. The
audit_logplugin remains loadable in 8.4 so that the old log keeps flowing during the transition. -
Install the component per Install the audit log filter. The install script creates
mysql.audit_log_filterandmysql.audit_log_user, then runsINSTALL COMPONENT. -
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.
-
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.
-
Cut over. Uninstall the plugin (
UNINSTALL PLUGIN audit_log;), removeaudit_log_*entries frommy.cnf, and leave the component as the sole audit writer. If you also had the transitionalaudit_log_filterplugin loaded, uninstall it as well. -
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¶
-
Confirm the component is live:
SELECT * FROM mysql.component WHERE component_urn = 'file://component_audit_log_filter'; -
Log in as a subject account, run a representative statement, and read the new log:
SELECT audit_log_read('{}');See Read log files.
-
Uninstall the legacy plugin and clear its settings from
my.cnf:UNINSTALL PLUGIN audit_log; -
Rotate once so new writes go to a fresh file under the component’s naming scheme:
SELECT audit_log_rotate(); -
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_filesto 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_filterandmysql.audit_log_user. Back up those tables before making bulk changes, and include them in your normalmysqldatabase backups. - Lifecycle events (
server_startup,server_shutdown, and theauditclass itself) are not valid filter targets — see Definition fields reference. audit_log_filter.event_modedefaults toREDUCED. If you relied on plugin logging for classes beyondconnection,general,table_access, andmessage, setevent_mode = FULLto match the broader class set.
Additional reading¶
- Upgrade from plugins to components
- Audit Log Filter overview
- Install the audit log filter
- Write filter definitions
- Functions, options, and variables
- Audit log plugin — legacy reference, with the deprecation notice