User and Permission Management in MySQL/MariaDB: Complete Security Guide

Introduction

Effective user and permission management is the cornerstone of database security in MySQL and MariaDB. Proper access control ensures that users can only perform authorized operations on specific databases and tables, protecting sensitive data from unauthorized access, modification, or deletion. In an era where data breaches are increasingly common and costly, implementing robust user and permission management is not just a best practice—it's a necessity.

MySQL and MariaDB provide a sophisticated privilege system that operates at multiple levels, from global server privileges down to individual column permissions. This granular control allows database administrators to implement the principle of least privilege, where each user receives only the minimum permissions necessary to perform their job functions. Understanding this system is essential for anyone responsible for database security and administration.

This comprehensive guide explores every aspect of MySQL/MariaDB user and permission management, from creating users and assigning basic privileges to implementing advanced security features like role-based access control, auditing user activities, and troubleshooting permission issues. Whether you're setting up a new database server or auditing an existing installation, this guide provides the knowledge and practical examples needed to implement secure, maintainable access control.

Prerequisites

Before diving into user and permission management, ensure you have:

System Requirements

  • MySQL 5.7+, MySQL 8.0+, or MariaDB 10.3+ installed
  • Access to a Linux server (Ubuntu 20.04+, CentOS 7+, or Debian 10+)
  • Root or administrative access to MySQL/MariaDB
  • Sudo or root access to the operating system

MySQL Access

  • Ability to connect as the MySQL root user
  • Knowledge of the root password
  • MySQL client tools installed

Knowledge Requirements

  • Basic SQL query syntax
  • Understanding of database concepts (databases, tables, users)
  • Linux command line fundamentals
  • Basic networking concepts for remote access

Recommended Tools

  • MySQL Workbench or similar GUI tool (optional)
  • Terminal emulator for command-line access
  • Text editor for configuration files

Understanding MySQL Privilege System

Privilege Levels

MySQL/MariaDB implements a hierarchical privilege system with five distinct levels:

1. Global Privileges: Apply to all databases on the server

  • Stored in the mysql.user table
  • Examples: CREATE USER, SUPER, RELOAD

2. Database Privileges: Apply to all objects within a specific database

  • Stored in the mysql.db table
  • Examples: CREATE, DROP, GRANT OPTION on a database

3. Table Privileges: Apply to all columns in a specific table

  • Stored in the mysql.tables_priv table
  • Examples: SELECT, INSERT, UPDATE, DELETE on a table

4. Column Privileges: Apply to specific columns in a table

  • Stored in the mysql.columns_priv table
  • Examples: SELECT or UPDATE on specific columns

5. Routine Privileges: Apply to stored procedures and functions

  • Stored in the mysql.procs_priv table
  • Examples: EXECUTE, ALTER ROUTINE

Common Privilege Types

Data Manipulation:

  • SELECT: Read data from tables
  • INSERT: Add new rows to tables
  • UPDATE: Modify existing data
  • DELETE: Remove rows from tables

Database Structure:

  • CREATE: Create databases and tables
  • ALTER: Modify table structures
  • DROP: Delete databases and tables
  • INDEX: Create or drop indexes

Administrative:

  • GRANT OPTION: Grant privileges to other users
  • SUPER: Administrative operations
  • RELOAD: Reload grant tables, flush privileges
  • SHUTDOWN: Shut down the MySQL server
  • PROCESS: View all processes
  • REPLICATION SLAVE: For replication slaves
  • REPLICATION CLIENT: Query replication status

Special:

  • ALL PRIVILEGES: All available privileges (except GRANT OPTION)
  • USAGE: Synonym for "no privileges" (login only)

Authentication Methods

mysql_native_password: Traditional MySQL authentication (default in MySQL 5.7)

caching_sha2_password: More secure, default in MySQL 8.0+

auth_socket: Uses operating system credentials (Linux)

PAM Authentication: Integration with system PAM (MariaDB)

Step-by-Step User Management

Step 1: Connect to MySQL as Root

Connect to MySQL with administrative privileges:

mysql -u root -p

Or using sudo authentication:

sudo mysql

Check your current connection:

SELECT USER(), CURRENT_USER(), DATABASE();

Step 2: View Existing Users

List all users in the system:

-- View all users
SELECT User, Host FROM mysql.user;

-- View users with more details
SELECT User, Host, account_locked, password_expired
FROM mysql.user
ORDER BY User, Host;

-- Check authentication methods
SELECT User, Host, plugin
FROM mysql.user
WHERE User != '';

Step 3: Create Basic Users

Create users with different authentication methods:

-- Create user with password (MySQL 5.7 style)
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';

-- Create user with specific authentication plugin (MySQL 8.0+)
CREATE USER 'app_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'SecurePassword123!';

-- Create user accessible from any host
CREATE USER 'remote_user'@'%' IDENTIFIED BY 'SecurePassword123!';

-- Create user from specific IP address
CREATE USER 'admin_user'@'192.168.1.100' IDENTIFIED BY 'SecurePassword123!';

-- Create user from IP range
CREATE USER 'network_user'@'192.168.1.%' IDENTIFIED BY 'SecurePassword123!';

-- Create user without password (not recommended)
CREATE USER 'test_user'@'localhost';

Step 4: Grant Basic Privileges

Grant privileges to users for specific databases:

-- Grant all privileges on a specific database
GRANT ALL PRIVILEGES ON myapp_db.* TO 'app_user'@'localhost';

-- Grant specific privileges on a database
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'app_user'@'localhost';

-- Grant SELECT only on a database
GRANT SELECT ON myapp_db.* TO 'readonly_user'@'localhost';

-- Grant privileges on specific table
GRANT SELECT, INSERT ON myapp_db.users TO 'limited_user'@'localhost';

-- Grant column-specific privileges
GRANT SELECT (id, username, email) ON myapp_db.users TO 'limited_user'@'localhost';

-- Apply privilege changes
FLUSH PRIVILEGES;

Step 5: Grant Administrative Privileges

Create administrative users with different levels of access:

-- Create database administrator (DBA)
CREATE USER 'dba_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT ALL PRIVILEGES ON *.* TO 'dba_user'@'localhost' WITH GRANT OPTION;

-- Create backup user
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER ON *.* TO 'backup_user'@'localhost';
GRANT RELOAD, PROCESS ON *.* TO 'backup_user'@'localhost';

-- Create replication user
CREATE USER 'replication_user'@'%' IDENTIFIED BY 'SecurePassword123!';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'replication_user'@'%';

-- Create monitoring user
CREATE USER 'monitor_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'monitor_user'@'localhost';
GRANT SELECT ON performance_schema.* TO 'monitor_user'@'localhost';

-- Apply changes
FLUSH PRIVILEGES;

Step 6: View User Privileges

Check what privileges a user has:

-- Show privileges for current user
SHOW GRANTS;

-- Show privileges for specific user
SHOW GRANTS FOR 'app_user'@'localhost';

-- Show detailed privilege information
SELECT * FROM mysql.user WHERE User = 'app_user'\G

-- Show database-level privileges
SELECT * FROM mysql.db WHERE User = 'app_user'\G

-- Show table-level privileges
SELECT * FROM mysql.tables_priv WHERE User = 'app_user'\G

Step 7: Modify User Privileges

Update existing user privileges:

-- Add additional privileges
GRANT DELETE ON myapp_db.* TO 'app_user'@'localhost';

-- Remove specific privileges
REVOKE DELETE ON myapp_db.* FROM 'app_user'@'localhost';

-- Remove all privileges for a database
REVOKE ALL PRIVILEGES ON myapp_db.* FROM 'app_user'@'localhost';

-- Remove all privileges globally
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'app_user'@'localhost';

-- Apply changes
FLUSH PRIVILEGES;

Step 8: Modify User Properties

Change user passwords and account properties:

-- Change user password
ALTER USER 'app_user'@'localhost' IDENTIFIED BY 'NewSecurePassword456!';

-- Change authentication method
ALTER USER 'app_user'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'SecurePassword123!';

-- Expire password (force change on next login)
ALTER USER 'app_user'@'localhost' PASSWORD EXPIRE;

-- Set password expiration policy
ALTER USER 'app_user'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;

-- Never expire password
ALTER USER 'app_user'@'localhost' PASSWORD EXPIRE NEVER;

-- Lock user account
ALTER USER 'app_user'@'localhost' ACCOUNT LOCK;

-- Unlock user account
ALTER USER 'app_user'@'localhost' ACCOUNT UNLOCK;

-- Set connection limit
ALTER USER 'app_user'@'localhost' WITH MAX_USER_CONNECTIONS 10;

Step 9: Rename and Delete Users

Manage user accounts:

-- Rename user
RENAME USER 'old_username'@'localhost' TO 'new_username'@'localhost';

-- Delete user (removes all privileges)
DROP USER 'app_user'@'localhost';

-- Delete multiple users
DROP USER 'user1'@'localhost', 'user2'@'localhost';

-- Delete user if exists (no error if doesn't exist)
DROP USER IF EXISTS 'app_user'@'localhost';

Step 10: Implement Role-Based Access Control (MySQL 8.0+)

Create and use roles for easier permission management:

-- Create roles
CREATE ROLE 'app_developer', 'app_reader', 'app_admin';

-- Grant privileges to roles
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'app_developer';
GRANT SELECT ON myapp_db.* TO 'app_reader';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'app_admin';

-- Assign roles to users
CREATE USER 'john'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT 'app_developer' TO 'john'@'localhost';

-- Set default role
SET DEFAULT ROLE 'app_developer' TO 'john'@'localhost';

-- View role grants
SHOW GRANTS FOR 'john'@'localhost' USING 'app_developer';

-- Revoke role from user
REVOKE 'app_developer' FROM 'john'@'localhost';

-- Drop role
DROP ROLE 'app_developer';

Advanced Permission Scenarios

Creating Application-Specific Users

Create users for different application components:

-- Web application user
CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'webapp'@'localhost';
GRANT EXECUTE ON myapp_db.* TO 'webapp'@'localhost';

-- API user with limited access
CREATE USER 'api_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT ON myapp_db.users TO 'api_user'@'localhost';
GRANT SELECT ON myapp_db.products TO 'api_user'@'localhost';
GRANT INSERT ON myapp_db.orders TO 'api_user'@'localhost';

-- Reporting user (read-only)
CREATE USER 'reports'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT ON myapp_db.* TO 'reports'@'localhost';

-- Batch processing user
CREATE USER 'batch_processor'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.transactions TO 'batch_processor'@'localhost';
GRANT SELECT ON myapp_db.users TO 'batch_processor'@'localhost';

FLUSH PRIVILEGES;

Implementing Row-Level Security

Use views to implement row-level security:

-- Create base table
CREATE TABLE myapp_db.employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    department VARCHAR(50),
    salary DECIMAL(10,2),
    email VARCHAR(100)
);

-- Create view for HR department
CREATE VIEW myapp_db.hr_employees AS
SELECT id, name, department, salary, email
FROM myapp_db.employees
WHERE department = 'HR';

-- Create view for other departments (no salary)
CREATE VIEW myapp_db.department_employees AS
SELECT id, name, department, email
FROM myapp_db.employees;

-- Grant access to views only
CREATE USER 'hr_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT, INSERT, UPDATE ON myapp_db.hr_employees TO 'hr_user'@'localhost';

CREATE USER 'dept_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT SELECT ON myapp_db.department_employees TO 'dept_user'@'localhost';

FLUSH PRIVILEGES;

Securing Stored Procedures

Control access to stored procedures:

-- Create stored procedure
DELIMITER //
CREATE PROCEDURE myapp_db.update_user_email(
    IN user_id INT,
    IN new_email VARCHAR(100)
)
SQL SECURITY DEFINER
BEGIN
    UPDATE myapp_db.users
    SET email = new_email
    WHERE id = user_id;
END //
DELIMITER ;

-- Grant execution privilege
CREATE USER 'proc_user'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT EXECUTE ON PROCEDURE myapp_db.update_user_email TO 'proc_user'@'localhost';

-- User can execute procedure without direct table access
FLUSH PRIVILEGES;

Managing Temporary Privileges

Grant temporary elevated privileges:

-- Grant temporary admin access
GRANT ALL PRIVILEGES ON myapp_db.* TO 'temp_admin'@'localhost';
FLUSH PRIVILEGES;

-- After maintenance, revoke
REVOKE ALL PRIVILEGES ON myapp_db.* FROM 'temp_admin'@'localhost';
GRANT SELECT ON myapp_db.* TO 'temp_admin'@'localhost';
FLUSH PRIVILEGES;

Security Best Practices Implementation

Implement Password Policies

Configure password validation (MySQL 8.0+):

-- Install password validation component
INSTALL COMPONENT 'file://component_validate_password';

-- Check password validation settings
SHOW VARIABLES LIKE 'validate_password%';

-- Configure password policy
SET GLOBAL validate_password.length = 12;
SET GLOBAL validate_password.mixed_case_count = 1;
SET GLOBAL validate_password.number_count = 1;
SET GLOBAL validate_password.special_char_count = 1;
SET GLOBAL validate_password.policy = 'STRONG';

In my.cnf:

[mysqld]
validate_password.length = 12
validate_password.mixed_case_count = 1
validate_password.number_count = 1
validate_password.special_char_count = 1
validate_password.policy = STRONG

Enable Audit Logging

Track user activities:

-- Install audit plugin (MariaDB)
INSTALL PLUGIN server_audit SONAME 'server_audit.so';

-- Configure audit settings
SET GLOBAL server_audit_logging = ON;
SET GLOBAL server_audit_events = 'CONNECT,QUERY,TABLE';
SET GLOBAL server_audit_file_path = '/var/log/mysql/audit.log';

For MySQL Enterprise:

-- Install audit log plugin
INSTALL PLUGIN audit_log SONAME 'audit_log.so';

-- Configure audit settings
SET GLOBAL audit_log_policy = 'ALL';
SET GLOBAL audit_log_format = 'JSON';

Implement Connection Security

Require SSL/TLS for connections:

-- Require SSL for user
CREATE USER 'secure_user'@'%' IDENTIFIED BY 'SecurePassword123!' REQUIRE SSL;

-- Require specific SSL certificate
CREATE USER 'cert_user'@'%' IDENTIFIED BY 'SecurePassword123!'
REQUIRE X509;

-- Require specific issuer
CREATE USER 'issuer_user'@'%' IDENTIFIED BY 'SecurePassword123!'
REQUIRE ISSUER '/C=US/ST=CA/L=City/O=Company/CN=CA';

-- Alter existing user to require SSL
ALTER USER 'app_user'@'localhost' REQUIRE SSL;

Implement Account Resource Limits

Control resource usage:

-- Create user with resource limits
CREATE USER 'limited_user'@'localhost' IDENTIFIED BY 'SecurePassword123!'
WITH MAX_QUERIES_PER_HOUR 1000
     MAX_UPDATES_PER_HOUR 500
     MAX_CONNECTIONS_PER_HOUR 100
     MAX_USER_CONNECTIONS 5;

-- Modify existing user limits
ALTER USER 'app_user'@'localhost'
WITH MAX_QUERIES_PER_HOUR 5000
     MAX_USER_CONNECTIONS 10;

Monitoring and Auditing

Monitor Active Connections

View current user connections:

-- Show all connections
SELECT * FROM information_schema.PROCESSLIST;

-- Show connections by user
SELECT User, Host, DB, Command, Time, State
FROM information_schema.PROCESSLIST
WHERE User = 'app_user';

-- Count connections per user
SELECT User, COUNT(*) as connection_count
FROM information_schema.PROCESSLIST
GROUP BY User;

-- Show long-running queries
SELECT User, Host, DB, Time, State, Info
FROM information_schema.PROCESSLIST
WHERE Command != 'Sleep'
  AND Time > 60
ORDER BY Time DESC;

Audit User Activities

Create audit queries:

-- Check last password changes
SELECT User, Host, password_last_changed
FROM mysql.user
WHERE password_last_changed IS NOT NULL
ORDER BY password_last_changed DESC;

-- Check locked accounts
SELECT User, Host, account_locked
FROM mysql.user
WHERE account_locked = 'Y';

-- Check password expiration status
SELECT User, Host, password_expired, password_lifetime
FROM mysql.user;

-- Check users with SUPER privilege
SELECT User, Host FROM mysql.user WHERE Super_priv = 'Y';

-- Check users with GRANT privilege
SELECT User, Host FROM mysql.user WHERE Grant_priv = 'Y';

Create User Audit Script

#!/bin/bash
# MySQL User Audit Script

sudo mysql -e "
SELECT 'Total Users' as Metric, COUNT(*) as Count FROM mysql.user
UNION ALL
SELECT 'Users with Global Privileges', COUNT(*) FROM mysql.user WHERE Select_priv = 'Y' OR Insert_priv = 'Y'
UNION ALL
SELECT 'Locked Accounts', COUNT(*) FROM mysql.user WHERE account_locked = 'Y'
UNION ALL
SELECT 'Expired Passwords', COUNT(*) FROM mysql.user WHERE password_expired = 'Y'
UNION ALL
SELECT 'Wildcard Host Users', COUNT(*) FROM mysql.user WHERE Host = '%';
"

Verification and Testing

Test User Permissions

# Test connection as specific user
mysql -u app_user -p -h localhost -e "SELECT DATABASE(), USER();"

# Test SELECT permission
mysql -u app_user -p myapp_db -e "SELECT * FROM users LIMIT 1;"

# Test INSERT permission
mysql -u app_user -p myapp_db -e "INSERT INTO test_table (data) VALUES ('test');"

# Test UPDATE permission
mysql -u app_user -p myapp_db -e "UPDATE test_table SET data='updated' WHERE id=1;"

# Test DELETE permission
mysql -u app_user -p myapp_db -e "DELETE FROM test_table WHERE id=1;"

# Test denied permission (should fail)
mysql -u readonly_user -p myapp_db -e "DROP TABLE test_table;"

Verify Privilege Configuration

-- Verify user exists
SELECT COUNT(*) as user_exists
FROM mysql.user
WHERE User = 'app_user' AND Host = 'localhost';

-- Check specific privilege
SELECT User, Host, Select_priv, Insert_priv, Update_priv, Delete_priv
FROM mysql.user
WHERE User = 'app_user';

-- Verify database access
SELECT User, Host, Db, Select_priv, Insert_priv, Update_priv, Delete_priv
FROM mysql.db
WHERE User = 'app_user' AND Db = 'myapp_db';

-- Check for privilege escalation
SELECT User, Host FROM mysql.user WHERE Grant_priv = 'Y';

Troubleshooting

Access Denied Errors

Issue: ERROR 1045 (28000): Access denied for user

Solution: Verify user credentials and host:

-- Check if user exists
SELECT User, Host FROM mysql.user WHERE User = 'app_user';

-- Verify authentication plugin
SELECT User, Host, plugin FROM mysql.user WHERE User = 'app_user';

-- Reset password
ALTER USER 'app_user'@'localhost' IDENTIFIED BY 'NewPassword123!';
FLUSH PRIVILEGES;

-- Check connection from correct host
-- User must connect from matching host in user@host definition

From command line:

# Check MySQL error log
sudo tail -f /var/log/mysql/error.log

# Test connection with verbose error
mysql -u app_user -p -h localhost -v -e "SELECT 1;"

Permission Denied on Operations

Issue: ERROR 1142 (42000): command denied to user

Solution: Grant necessary privileges:

-- Check current privileges
SHOW GRANTS FOR 'app_user'@'localhost';

-- Grant missing privilege
GRANT CREATE ON myapp_db.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;

-- Verify privilege was granted
SHOW GRANTS FOR 'app_user'@'localhost';

Host Not Allowed Errors

Issue: ERROR 1130 (HY000): Host '192.168.1.100' is not allowed to connect

Solution: Create user for specific host:

-- Create user for specific IP
CREATE USER 'app_user'@'192.168.1.100' IDENTIFIED BY 'SecurePassword123!';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'app_user'@'192.168.1.100';

-- Or allow from any host (less secure)
CREATE USER 'app_user'@'%' IDENTIFIED BY 'SecurePassword123!';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'app_user'@'%';

FLUSH PRIVILEGES;

Check bind-address in my.cnf:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
bind-address = 0.0.0.0  # Allow external connections

Restart MySQL:

sudo systemctl restart mysql

Too Many Connections

Issue: ERROR 1040 (HY000): Too many connections

Solution: Adjust connection limits:

-- Check current connections
SHOW STATUS LIKE 'Threads_connected';
SHOW VARIABLES LIKE 'max_connections';

-- Increase max connections
SET GLOBAL max_connections = 200;

-- Check per-user limits
SELECT User, Host, max_user_connections FROM mysql.user;

-- Increase user connection limit
ALTER USER 'app_user'@'localhost' WITH MAX_USER_CONNECTIONS 20;

In my.cnf:

[mysqld]
max_connections = 200

Privilege Not Taking Effect

Issue: Granted privilege not working immediately

Solution: Flush privileges:

-- Flush privilege tables
FLUSH PRIVILEGES;

-- Or restart MySQL
-- sudo systemctl restart mysql

-- Force user to reconnect
SELECT * FROM information_schema.PROCESSLIST WHERE User = 'app_user';
-- Note process IDs and kill them
KILL <process_id>;

Best Practices Summary

1. Principle of Least Privilege

Grant only the minimum privileges necessary for each user to perform their tasks. Regularly review and audit user permissions.

2. Use Strong Passwords

Implement password policies requiring:

  • Minimum length of 12 characters
  • Mix of uppercase, lowercase, numbers, and special characters
  • Regular password rotation (90 days)
  • No password reuse

3. Avoid Using Root for Applications

Never use the root account for application connections. Create dedicated users with appropriate privileges.

4. Restrict Host Access

Use specific IP addresses or hostnames instead of '%' wildcard when possible:

-- Good
CREATE USER 'app_user'@'192.168.1.100' IDENTIFIED BY 'password';

-- Less secure
CREATE USER 'app_user'@'%' IDENTIFIED BY 'password';

5. Use Roles for Complex Environments

Implement role-based access control (RBAC) for easier management of permissions across multiple users.

6. Enable SSL/TLS

Require encrypted connections for all remote users:

CREATE USER 'remote_user'@'%' IDENTIFIED BY 'password' REQUIRE SSL;

7. Regular Security Audits

Schedule monthly security audits:

  • Review all user accounts
  • Check for unused accounts
  • Verify privilege assignments
  • Review audit logs
  • Check for wildcard host permissions

8. Document User Purposes

Maintain documentation for each database user:

  • Purpose and owner
  • Date created
  • Granted privileges
  • Review schedule
  • Contact information

9. Implement Account Expiration

Set expiration dates for temporary accounts:

ALTER USER 'temp_user'@'localhost' PASSWORD EXPIRE INTERVAL 30 DAY;

10. Monitor and Alert

Set up monitoring for:

  • Failed login attempts
  • Privilege escalation attempts
  • Unusual query patterns
  • Connection spikes
  • Locked accounts

Conclusion

Effective user and permission management in MySQL and MariaDB is fundamental to database security and operational efficiency. By following this comprehensive guide, you've learned how to create users with appropriate privileges, implement role-based access control, secure connections with SSL/TLS, audit user activities, and troubleshoot common permission issues.

The key to maintaining a secure MySQL/MariaDB environment is continuous vigilance through regular audits, adherence to the principle of least privilege, implementation of strong authentication mechanisms, monitoring of user activities, and staying updated with security best practices. Remember that security is not a one-time configuration but an ongoing process that requires regular attention and updates.

As your database environment grows, revisit your permission structure regularly to ensure it still meets your security requirements while supporting operational needs. Implement automated monitoring and alerting systems to detect anomalous activities, conduct regular security training for team members with database access, maintain comprehensive documentation of all user accounts and their purposes, and establish clear procedures for granting, modifying, and revoking privileges.

The foundation you've built with this guide will serve you well as you scale your database infrastructure and adapt to evolving security threats. Continue to stay informed about new security features in MySQL and MariaDB releases, participate in the database security community, and regularly test your security configurations to ensure they provide the protection your data deserves.