Audit filter with query and user info in one record possible?

I have an audit filter which checks which users have created/dropped/altered users in the database.

I need user and host in the info however I cannot seem to find a way to include it in one record.

What I get in the audit filter log is something like :

“timestamp”: “2026-03-05 10:52:11”,
“id”: 349074,
“class”: “query”,
“event”: “query_start”,
“connection_id”: 174655,
“query_data”: {
“query”: “ALTER USER ‘test_user’@‘%’ IDENTIFIED BY ”,
“status”: 0,
“sql_command”: “alter_user”}

My current filter is:

SELECT audit_log_filter_set_filter(‘capture_required_events’, '{

“filter”: {

"class": \[

  {

    "name": "connection",

    "event": \[

      { "name": "connect" },

      { "name": "disconnect" },

      { "name": "failed_login" }

    \]

  },

  {

    "name": "query",

    "event": \[

      {

        "name": "start",

        "log": {

          "or": \[

            { "field": { "name": "sql_command_id", "value": "create_user" } },

            { "field": { "name": "sql_command_id", "value": "alter_user" } },

            { "field": { "name": "sql_command_id", "value": "drop_user" } }

          \]

        }

      }

    \]

  }

\]

}

}');

Please try this filter:

{
  "filter": {
    "class": {
      "name": "general",
      "event": {
        "name": "status",
        "log": {
          "or": [{
            "field": { 
              "name": "general_sql_command.str",
              "value": "create_user" 
            }
          },
          {
            "field": {
              "name": "general_sql_command.str",
              "value": "alter_user"
            }
          },
          {
            "field": {
              "name": "general_sql_command.str",
              "value": "drop_user"
            }
          }]
        }
      }
    }
  }
}

Here’s a sample from the audit log in XML format:

  <AUDIT_RECORD>
    <NAME>Status</NAME>
    <RECORD_ID>2_2026-03-06T00:43:31</RECORD_ID>
    <TIMESTAMP>2026-03-06T00:43:31</TIMESTAMP>
    <COMMAND_CLASS>General</COMMAND_CLASS>
    <CONNECTION_ID>52</CONNECTION_ID>
    <HOST>localhost</HOST>
    <IP></IP>
    <USER>root[root] @ localhost []</USER>
    <STATUS>0</STATUS>
    <SQLTEXT>ALTER USER 'test'@'localhost' IDENTIFIED BY &lt;secret&gt;</SQLTEXT>
  </AUDIT_RECORD>

Thanks.

Not sure why this is not working for me.

It is not logging anything in the audit_filter_log

mysql> SELECT * FROM mysql.audit_log_filter;
±----------±------------------------±--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| filter_id | name | filter |
±----------±------------------------±--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1 | capture_required_events | {“filter”: {“class”: {“name”: “general”, “event”: {“log”: {“or”: [{“field”: {“name”: “general_sql_command.str”, “value”: “create_user”}}, {“field”: {“name”: “general_sql_command.str”, “value”: “alter_user”}}, {“field”: {“name”: “general_sql_command.str”, “value”: “drop_user”}}]}, “name”: “status”}}}} |
±----------±------------------------±--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM mysql.audit_log_user;
±---------±---------±------------------------+
| username | userhost | filtername |
±---------±---------±------------------------+
| % | % | capture_required_events |
±---------±---------±------------------------+
1 row in set (0.00 sec)

SELECT audit_log_filter_set_filter(‘capture_required_events’, ‘{
“filter”: {
“class”: {
“name”: “general”,
“event”: {
“name”: “status”,
“log”: {
“or”: [{
“field”: {
“name”: “general_sql_command.str”,
“value”: “create_user”
}
},
{
“field”: {
“name”: “general_sql_command.str”,
“value”: “alter_user”
}
},
{
“field”: {
“name”: “general_sql_command.str”,
“value”: “drop_user”
}
}]
}
}
}
}
}’);

I also tried simply using the filter you sent and nothing is getting logged. Not sure what I’m doing incorrectly.
SET @f = '{
  "filter": {
    "class": {
      "name": "general",
      "event": {
        "name": "status",
        "log": {
          "or": [{
            "field": { 
              "name": "general_sql_command.str",
              "value": "create_user" 
            }
          },
          {
            "field": {
              "name": "general_sql_command.str",
              "value": "alter_user"
            }
          },
          {
            "field": {
              "name": "general_sql_command.str",
              "value": "drop_user"
            }
          }]
        }
      }
    }
  }
}' ;

SELECT audit_log_filter_set_filter('capture_required_events', @f);
SELECT audit_log_filter_set_user('%', 'capture_required_events');

Could you please confirm your database version? Also, are you using Percona Server for MySQL?

Im using percona 8.4.5. thanks

So, unfortunately, this is not possible in v8.4.5. What you can do in your current version is to collect the query events + general status events:

  SELECT audit_log_filter_set_filter(
    'log_user_mgmt_with_executor_845',
    '{
      "filter": {
        "class": [
          {
            "name": "query",
            "event": {
              "name": "status_end",
              "log": {
                "or": [
                  { "field": { "name": "sql_command_id", "value": "create_user" } },
                  { "field": { "name": "sql_command_id", "value": "alter_user" } },
                  { "field": { "name": "sql_command_id", "value": "drop_user" } }
                ]
              }
            }
          },
          {
            "name": "general",
            "event": {
              "name": "status",
              "log": true
            }
          }
        ]
      }
    }'
  );

The sample output would be:

  {
    "timestamp": "2026-03-16 12:36:18",
    "id": 8,
    "class": "general",
    "event": "status",
    "connection_id": 75,
    "account": { "user": "root[root] @ localhost []", "host": "localhost" },
    "login": { "user": "root[root] @ localhost []", "ip": "", "proxy": "" },
    "general_data": { "status": 0 }
  },
  {
    "timestamp": "2026-03-16 12:36:18",
    "id": 9,
    "class": "general",
    "event": "status",
    "connection_id": 75,
    "account": { "user": "root[root] @ localhost []", "host": "localhost" },
    "login": { "user": "root[root] @ localhost []", "ip": "", "proxy": "" },
    "general_data": { "status": 1064 }
  },
  {
    "timestamp": "2026-03-16 12:36:23",
    "id": 10,
    "class": "query",
    "event": "query_status_end",
    "connection_id": 75,
    "query_data": {
      "query": "drop user 'test01'@'localhost'",
      "status": 0,
      "sql_command": "drop_user"}
  },
  {
    "timestamp": "2026-03-16 12:36:23",
    "id": 11,
    "class": "general",
    "event": "status",
    "connection_id": 75,
    "account": { "user": "root[root] @ localhost []", "host": "localhost" },
    "login": { "user": "root[root] @ localhost []", "ip": "", "proxy": "" },
    "general_data": { "status": 0 }
  }

You correlate each event by their connection_id as we see above.

Thanks. What version can do I get the audit log to have the combined information in one audit record? Thanks.

I suggest testing version 8.4.7 first on your test or staging environment before upgrading production servers.