How to Audit MySQL Login Attempts Without Enabling General Query Log


48 views

In high-traffic production environments, tracking database access attempts becomes crucial for security auditing while maintaining performance. The standard general_log approach creates significant overhead by logging all queries - a dealbreaker for performance-sensitive systems.

MySQL offers several targeted methods for authentication tracking:

-- Method 1: Error log configuration
[mysqld]
log_error = /var/log/mysql/error.log
log_warnings = 2  # Captures failed auth attempts

-- Method 2: Performance Schema setup
UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES'
WHERE NAME LIKE 'events_statements%';

UPDATE performance_schema.setup_instruments
SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME = 'statement/sql/connect';

For comprehensive auditing without performance impact:

-- MySQL Enterprise Audit plugin (requires license)
INSTALL PLUGIN audit_log SONAME 'audit_log.so';

-- Configuration options:
[mysqld]
audit_log_format=JSON
audit_log_policy=ALL
audit_log_include_accounts=TRUE

For granular control with minimal overhead:

CREATE TABLE login_audit (
    event_time TIMESTAMP,
    user_host VARCHAR(80),
    status ENUM('SUCCESS','FAILURE'),
    connection_id BIGINT
);

DELIMITER //
CREATE TRIGGER after_connection
AFTER CONNECT ON *.*
FOR EACH STATEMENT
BEGIN
    INSERT INTO login_audit 
    VALUES(NOW(), CURRENT_USER(), 'SUCCESS', CONNECTION_ID());
END//

CREATE TRIGGER after_auth_failure
AFTER SERVER_ERROR ON *.*
FOR EACH STATEMENT
BEGIN
    IF (ERROR_NUMBER() = 1045) THEN
        INSERT INTO login_audit 
        VALUES(NOW(), '@'+@@hostname, 'FAILURE', CONNECTION_ID());
    END IF;
END//
DELIMITER ;

For managed database services:

  • AWS RDS: Enable Enhanced Monitoring with DB authentication events
  • Google Cloud SQL: Use Cloud Audit Logs with admin activity tracking
  • Azure Database: Configure Diagnostic Settings to stream logs

Example log processing with grep:

# Find failed attempts in error log
grep "Access denied" /var/log/mysql/error.log | 
awk '{print $1, $2, $5, $6, $NF}' > failed_logins.txt

# Generate hourly report
mysql -e "SELECT 
    DATE_FORMAT(event_time, '%Y-%m-%d %H:00') AS hour,
    status,
    COUNT(*) AS attempts
FROM login_audit
GROUP BY hour, status
ORDER BY hour DESC;"

In production environments, tracking authentication attempts (both successful and failed) is crucial for security auditing and troubleshooting. While MySQL's general_log might seem like the obvious solution, its performance impact makes it unsuitable for high-traffic databases.

Here are three production-friendly methods to log MySQL authentication events:

MySQL Enterprise Edition includes a native audit plugin, but for open-source users, MariaDB's audit plugin works perfectly:

INSTALL PLUGIN server_audit SONAME 'server_audit.so';
SET GLOBAL server_audit_events='connect,query';
SET GLOBAL server_audit_logging=ON;

For MySQL 5.7+ and MariaDB 10.0+, the performance_schema offers low-overhead monitoring:

UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES'
WHERE NAME LIKE 'events_statements%';

SELECT EVENT_NAME, COUNT_STAR 
FROM performance_schema.events_statements_summary_global_by_event_name
WHERE EVENT_NAME LIKE '%connect%';

Configure MySQL to send auth logs to syslog (works on most Linux systems):

SET GLOBAL log_warnings = 2;
SET GLOBAL log_error_verbosity = 3;

Then configure syslog/rsyslog to capture these messages to a dedicated file.

For versions without plugin support, create a login tracking table and trigger:

CREATE TABLE login_audit (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(128),
    event_time DATETIME,
    status ENUM('SUCCESS','FAILURE'),
    source_host VARCHAR(60),
    client_program VARCHAR(255)
);

DELIMITER //
CREATE TRIGGER after_connection_track
AFTER CONNECT ON *.*
FOR EACH STATEMENT
BEGIN
    INSERT INTO login_audit
    VALUES (NULL, USER(), NOW(), 
           IF(COUNT_ERRORS()>0, 'FAILURE', 'SUCCESS'),
           SUBSTRING_INDEX(USER(), '@', -1),
           PROGRAM_NAME());
END//
DELIMITER ;

When implementing any logging solution in production:

  • Rotate logs frequently to prevent disk filling
  • Consider sampling rather than logging every event for extremely busy servers
  • Monitor the logging overhead (typically 2-5% CPU impact)

Use tools like grep, awk or specialized log analyzers:

# Find failed login attempts
grep "Access denied" /var/log/mysql/error.log | 
awk '{print $1,$2,$3,$8,$9}' | 
sort | uniq -c | sort -n

For cloud environments, consider forwarding logs to centralized services like AWS CloudWatch or ELK stack.