Set up comprehensive MySQL monitoring with Netdata for real-time database performance metrics, query analysis, and automated alerts. Monitor connection pools, slow queries, and resource usage with production-grade alerting.
Prerequisites
- MySQL or MariaDB server running
- Root or sudo access
- Basic MySQL administration knowledge
What this solves
Netdata provides real-time MySQL monitoring with zero-configuration autodiscovery, detailed performance metrics, and built-in alerting. This tutorial shows you how to configure Netdata to monitor MySQL databases, set up performance alerts for critical metrics like slow queries and connection pool exhaustion, and create custom dashboards for database health monitoring.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions of all packages.
sudo apt update && sudo apt upgrade -y
Install Netdata monitoring agent
Install Netdata using the official one-line installer script, which automatically detects your system and installs the appropriate packages.
bash <(curl -Ss https://my-netdata.io/kickstart.sh) --stable-channel --disable-telemetry
The installer will compile Netdata from source and install it with systemd integration. This process takes 3-5 minutes depending on your system.
Install MySQL development packages
Install MySQL client libraries that Netdata requires for database connectivity and metric collection.
sudo apt install -y libmysqlclient-dev mysql-client
Create MySQL monitoring user
Create a dedicated MySQL user for Netdata with minimal privileges required for monitoring. This follows the principle of least privilege for security.
mysql -u root -p
Run these SQL commands to create the monitoring user:
CREATE USER 'netdata'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT USAGE ON . TO 'netdata'@'localhost';
GRANT REPLICATION CLIENT ON . TO 'netdata'@'localhost';
GRANT PROCESS ON . TO 'netdata'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Configure Netdata MySQL collector
Create the MySQL collector configuration file to specify database connection details and monitoring parameters.
# MySQL monitoring configuration
Multiple MySQL instances can be monitored
localhost:
name: 'local_mysql'
host: '127.0.0.1'
port: 3306
user: 'netdata'
pass: 'StrongPassword123!'
update_every: 5
priority: 90000
retries: 5
# Enable detailed metrics collection
my_cnf: '/etc/mysql/my.cnf'
socket: '/var/run/mysqld/mysqld.sock'
# Monitor specific databases (optional)
# exclude_databases: 'information_schema performance_schema sys mysql'
# SSL configuration (if MySQL uses SSL)
# ssl_ca: '/path/to/ca-cert.pem'
# ssl_cert: '/path/to/client-cert.pem'
# ssl_key: '/path/to/client-key.pem'
Enable Python plugins for MySQL monitoring
Enable the Python plugin system and ensure MySQL collector is active by editing the main configuration.
[plugins]
# Enable python.d plugin
python.d = yes
[plugin:python.d]
# MySQL monitoring enabled
mysql = yes
# Update frequency for MySQL metrics (seconds)
update every = 5
# Command timeout for MySQL queries
command options =
Configure MySQL performance alerts
Create custom alert rules for MySQL performance monitoring by creating an alert configuration file.
# MySQL Connection Pool Alerts
alarm: mysql_connections_usage
on: mysql_localhost.connections
calc: $used * 100 / $max
warn: $this > 70
crit: $this > 85
every: 10s
units: %
info: MySQL connection pool usage percentage
to: sysadmin
MySQL Slow Queries Alert
alarm: mysql_slow_queries_rate
on: mysql_localhost.slow_queries
calc: $slow_queries
warn: $this > 5
crit: $this > 20
every: 60s
units: queries/s
info: MySQL slow queries per second
to: dba
MySQL Query Cache Hit Rate
alarm: mysql_qcache_hit_rate
on: mysql_localhost.qcache_ops
calc: $hits * 100 / ($hits + $inserts + $not_cached)
warn: $this < 80
crit: $this < 60
every: 60s
units: %
info: MySQL query cache hit rate percentage
to: dba
MySQL InnoDB Buffer Pool Usage
alarm: mysql_innodb_buffer_pool_usage
on: mysql_localhost.innodb_buffer_pool_pages
calc: $used * 100 / $total
warn: $this > 85
crit: $this > 95
every: 30s
units: %
info: MySQL InnoDB buffer pool usage percentage
to: sysadmin
MySQL Replication Lag (if using replication)
alarm: mysql_slave_lag
on: mysql_localhost.slave_lag
calc: $seconds
warn: $this > 30
crit: $this > 120
every: 30s
units: seconds
info: MySQL slave replication lag in seconds
to: dba
MySQL Lock Waits
alarm: mysql_innodb_lock_waits
on: mysql_localhost.innodb_lock_structs
calc: $lock_structs
warn: $this > 100
crit: $this > 500
every: 30s
units: locks
info: MySQL InnoDB lock structures count
to: dba
Configure email notifications
Set up email notifications for MySQL alerts by configuring the health notification system.
# Email notification configuration
SEND_EMAIL="YES"
DEFAULT_RECIPIENT_EMAIL="admin@example.com"
EMAIL_SENDER="netdata@example.com"
SMTP configuration
EMAIL_SMTP_SERVER="smtp.example.com"
EMAIL_SMTP_PORT="587"
EMAIL_SMTP_USERNAME="netdata@example.com"
EMAIL_SMTP_PASSWORD="your_smtp_password"
EMAIL_SMTP_SECURE="STARTTLS"
Role-based recipients
role_recipients_sysadmin="sysadmin@example.com"
role_recipients_dba="dba@example.com"
Notification frequency
DEFAULT_RECIPIENT_CUSTOM_FREQUENCIES="critical:10m, warning:1h"
Enable HTML email format
EMAIL_PLAINTEXT_ONLY="NO"
Enable and restart Netdata service
Restart Netdata to apply the MySQL monitoring configuration and alert rules.
sudo systemctl restart netdata
sudo systemctl enable netdata
sudo systemctl status netdata
Configure firewall for Netdata web interface
Open port 19999 to access the Netdata web dashboard from your local network or specific IP addresses.
sudo ufw allow from 192.168.1.0/24 to any port 19999
sudo ufw reload
Advanced MySQL monitoring configuration
Enable MySQL performance schema monitoring
Configure additional MySQL performance metrics by enabling Performance Schema monitoring in your MySQL configuration.
[mysqld]
Enable Performance Schema
performance_schema = ON
performance_schema_max_table_instances = 400
performance_schema_max_table_handles = 4000
performance_schema_events_statements_history_size = 20
performance_schema_events_statements_history_long_size = 1000
Enable slow query log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
Enable general log for debugging (disable in production)
general_log = 1
general_log_file = /var/log/mysql/general.log
Create advanced MySQL metrics collector
Configure Netdata to collect additional MySQL metrics including table statistics and custom queries.
advanced_mysql:
name: 'mysql_performance'
host: '127.0.0.1'
port: 3306
user: 'netdata'
pass: 'StrongPassword123!'
update_every: 10
# Custom queries for specific metrics
queries:
table_stats:
query: 'SELECT table_schema, COUNT(*) as table_count FROM information_schema.tables WHERE table_schema NOT IN ("information_schema", "performance_schema", "sys", "mysql") GROUP BY table_schema'
dimensions:
- name: 'table_count'
algorithm: 'absolute'
multiplier: 1
divisor: 1
connection_errors:
query: 'SHOW GLOBAL STATUS LIKE "Connection_errors%"'
dimensions:
- name: 'Connection_errors_accept'
- name: 'Connection_errors_internal'
- name: 'Connection_errors_max_connections'
- name: 'Connection_errors_peer_address'
- name: 'Connection_errors_select'
- name: 'Connection_errors_tcpwrap'
Verify your setup
Check that Netdata is running and collecting MySQL metrics correctly.
# Check Netdata service status
sudo systemctl status netdata
Verify MySQL plugin is loaded
sudo netdata -W debug 2>&1 | grep -i mysql
Check MySQL connectivity from Netdata
sudo -u netdata mysql -h 127.0.0.1 -u netdata -p -e "SHOW STATUS LIKE 'Uptime';"
Test alert configuration
sudo /usr/libexec/netdata/plugins.d/alarm-notify.sh test
View real-time MySQL metrics
curl -s http://localhost:19999/api/v1/charts | grep mysql
Access the Netdata web interface at http://your-server-ip:19999. Navigate to the MySQL section to see database performance charts including connections, queries per second, slow queries, and buffer pool usage.
Configure Slack notifications
Set up Slack webhook integration
Configure Netdata to send MySQL alerts to Slack channels for team notifications.
# Slack notification configuration
SEND_SLACK="YES"
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
DEFAULT_RECIPIENT_SLACK="#alerts"
Role-specific Slack channels
role_recipients_sysadmin="#sysadmin-alerts"
role_recipients_dba="#database-alerts"
Slack message customization
SLACK_CHANNEL="#netdata-alerts"
SLACK_USERNAME="NetdataBot"
SLACK_ICON_EMOJI=":exclamation:"
Message format
SLACK_DETAILED_MESSAGES="YES"
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| MySQL charts not appearing | Python MySQL module not installed | sudo pip3 install PyMySQL or sudo apt install python3-pymysql |
| Connection refused to MySQL | Wrong credentials or host | Test connection manually: mysql -h 127.0.0.1 -u netdata -p |
| Alerts not triggering | Alert configuration syntax error | Check logs: sudo journalctl -u netdata | grep -i health |
| Email notifications not working | SMTP configuration issues | Test email: sudo /usr/libexec/netdata/plugins.d/alarm-notify.sh test |
| High CPU usage from Netdata | Too frequent MySQL polling | Increase update_every from 5 to 10 seconds in MySQL config |
| Missing InnoDB metrics | MySQL user lacks PROCESS privilege | Grant privilege: GRANT PROCESS ON . TO 'netdata'@'localhost'; |
| Slow query alerts false positive | Threshold too low for workload | Adjust slow query alert threshold in /etc/netdata/health.d/mysql_custom.conf |
Performance tuning for MySQL monitoring
To optimize Netdata's impact on MySQL performance while maintaining comprehensive monitoring:
- Set MySQL collector
update_everyto 10-15 seconds for production systems - Use connection pooling by configuring
max_connectionsappropriately - Monitor only critical databases by using
exclude_databasesoption - Enable MySQL query cache to reduce repetitive query overhead
- Consider using a dedicated read-only replica for monitoring if available
For high-traffic MySQL instances, you may want to explore Prometheus-based MySQL monitoring which offers more granular control over metric collection frequency and retention.
Next steps
- Configure MariaDB monitoring with Prometheus and Grafana dashboards
- Implement MySQL backup automation with Percona XtraBackup
- Setup MySQL replication with GTID and automatic failover
- Configure MySQL connection pooling with ProxySQL 2.6
- Configure advanced Netdata MySQL custom queries and dashboards
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Script variables
SCRIPT_NAME="$(basename "$0")"
MYSQL_USER="${1:-netdata}"
ADMIN_EMAIL="${2:-admin@example.com}"
NETWORK_RANGE="${3:-127.0.0.1}"
# Function definitions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
usage() {
cat << EOF
Usage: $SCRIPT_NAME [mysql_user] [admin_email] [network_range]
Arguments:
mysql_user MySQL monitoring user (default: netdata)
admin_email Email for alerts (default: admin@example.com)
network_range Network/IP for dashboard access (default: 127.0.0.1)
Examples:
$SCRIPT_NAME
$SCRIPT_NAME netdata alerts@company.com 192.168.1.0/24
$SCRIPT_NAME monitoring admin@domain.com 10.0.0.0/8
EOF
exit 1
}
cleanup() {
log_error "Installation failed. Check logs above for details."
exit 1
}
trap cleanup ERR
check_prerequisites() {
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root or with sudo"
exit 1
fi
if ! command -v curl >/dev/null 2>&1; then
log_error "curl is required but not installed"
exit 1
fi
}
detect_distro() {
if [[ ! -f /etc/os-release ]]; then
log_error "Cannot detect distribution. /etc/os-release not found"
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
PKG_UPGRADE="apt upgrade -y"
FIREWALL_CMD="ufw"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf check-update || true"
PKG_INSTALL="dnf install -y"
PKG_UPGRADE="dnf update -y"
FIREWALL_CMD="firewall-cmd"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum check-update || true"
PKG_INSTALL="yum install -y"
PKG_UPGRADE="yum update -y"
FIREWALL_CMD="firewall-cmd"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
log_info "Detected distribution: $PRETTY_NAME"
log_info "Package manager: $PKG_MGR"
}
update_system() {
log_info "[1/8] Updating system packages..."
$PKG_UPDATE
$PKG_UPGRADE
}
install_netdata() {
log_info "[2/8] Installing Netdata monitoring agent..."
bash <(curl -Ss https://my-netdata.io/kickstart.sh) --stable-channel --disable-telemetry
}
configure_mysql_user() {
log_info "[3/8] Configuring MySQL monitoring user..."
if ! command -v mysql >/dev/null 2>&1; then
log_warn "MySQL client not found. Please create the monitoring user manually:"
cat << EOF
CREATE USER '$MYSQL_USER'@'localhost';
GRANT USAGE, REPLICATION CLIENT, PROCESS ON *.* TO '$MYSQL_USER'@'localhost';
FLUSH PRIVILEGES;
EOF
return
fi
# Try to create MySQL user automatically
if mysql -e "SELECT 1" >/dev/null 2>&1; then
mysql << EOF
CREATE USER IF NOT EXISTS '$MYSQL_USER'@'localhost';
GRANT USAGE, REPLICATION CLIENT, PROCESS ON *.* TO '$MYSQL_USER'@'localhost';
FLUSH PRIVILEGES;
EOF
log_info "MySQL user '$MYSQL_USER' created successfully"
else
log_warn "Cannot connect to MySQL. Please create the monitoring user manually."
fi
}
configure_netdata_mysql() {
log_info "[4/8] Configuring Netdata MySQL monitoring..."
NETDATA_CONFIG_DIR="/etc/netdata"
MYSQL_CONF_DIR="$NETDATA_CONFIG_DIR/python.d"
mkdir -p "$MYSQL_CONF_DIR"
cat > "$MYSQL_CONF_DIR/mysql.conf" << EOF
localhost:
name: 'local'
host: 'localhost'
port: 3306
user: '$MYSQL_USER'
update_every: 10
priority: 90100
EOF
chown netdata:netdata "$MYSQL_CONF_DIR/mysql.conf"
chmod 644 "$MYSQL_CONF_DIR/mysql.conf"
}
configure_alerts() {
log_info "[5/8] Configuring MySQL performance alerts..."
HEALTH_CONFIG_DIR="/etc/netdata/health.d"
mkdir -p "$HEALTH_CONFIG_DIR"
cat > "$HEALTH_CONFIG_DIR/mysql_custom.conf" << 'EOF'
# MySQL Connection Pool Usage
alarm: mysql_connections_usage
on: mysql_localhost.connections
calc: $active * 100 / $limit
warn: $this > 70
crit: $this > 85
every: 10s
units: %
info: MySQL connection pool usage percentage
to: sysadmin
# MySQL Slow Queries Alert
alarm: mysql_slow_queries_rate
on: mysql_localhost.slow_queries
calc: $slow_queries
warn: $this > 5
crit: $this > 20
every: 60s
units: queries/s
info: MySQL slow queries per second
to: dba
# MySQL Query Cache Hit Rate
alarm: mysql_qcache_hit_rate
on: mysql_localhost.qcache_ops
calc: $hits * 100 / ($hits + $inserts + $not_cached)
warn: $this < 80
crit: $this < 60
every: 60s
units: %
info: MySQL query cache hit rate percentage
to: dba
# MySQL InnoDB Buffer Pool Usage
alarm: mysql_innodb_buffer_pool_usage
on: mysql_localhost.innodb_buffer_pool_pages
calc: $used * 100 / $total
warn: $this > 85
crit: $this > 95
every: 30s
units: %
info: MySQL InnoDB buffer pool usage percentage
to: sysadmin
# MySQL Replication Lag
alarm: mysql_slave_lag
on: mysql_localhost.slave_lag
calc: $seconds
warn: $this > 30
crit: $this > 120
every: 30s
units: seconds
info: MySQL slave replication lag in seconds
to: dba
EOF
chown netdata:netdata "$HEALTH_CONFIG_DIR/mysql_custom.conf"
chmod 644 "$HEALTH_CONFIG_DIR/mysql_custom.conf"
}
configure_notifications() {
log_info "[6/8] Configuring email notifications..."
HEALTH_ALARM_NOTIFY="/etc/netdata/health_alarm_notify.conf"
# Backup original config if it exists
if [[ -f "$HEALTH_ALARM_NOTIFY" ]]; then
cp "$HEALTH_ALARM_NOTIFY" "$HEALTH_ALARM_NOTIFY.backup"
fi
cat > "$HEALTH_ALARM_NOTIFY" << EOF
SEND_EMAIL="YES"
DEFAULT_RECIPIENT_EMAIL="$ADMIN_EMAIL"
EMAIL_SENDER="netdata@\$(hostname -f)"
EMAIL_PLAINTEXT_ONLY="NO"
# Role-based recipients
role_recipients_sysadmin="$ADMIN_EMAIL"
role_recipients_dba="$ADMIN_EMAIL"
# Notification frequency
DEFAULT_RECIPIENT_CUSTOM_FREQUENCIES="critical:10m warning:1h"
EOF
chown netdata:netdata "$HEALTH_ALARM_NOTIFY"
chmod 644 "$HEALTH_ALARM_NOTIFY"
}
configure_firewall() {
log_info "[7/8] Configuring firewall for Netdata access..."
if [[ "$FIREWALL_CMD" == "ufw" ]]; then
if command -v ufw >/dev/null 2>&1; then
if [[ "$NETWORK_RANGE" == *"/"* ]] || [[ "$NETWORK_RANGE" == *"."*".0" ]]; then
ufw allow from "$NETWORK_RANGE" to any port 19999
else
ufw allow from "$NETWORK_RANGE" to any port 19999
fi
ufw --force enable >/dev/null 2>&1 || true
fi
elif [[ "$FIREWALL_CMD" == "firewall-cmd" ]]; then
if command -v firewall-cmd >/dev/null 2>&1; then
if systemctl is-active firewalld >/dev/null 2>&1; then
firewall-cmd --permanent --add-rich-rule="rule family=\"ipv4\" source address=\"$NETWORK_RANGE\" port protocol=\"tcp\" port=\"19999\" accept"
firewall-cmd --reload
fi
fi
fi
}
start_services() {
log_info "[8/8] Starting and enabling Netdata service..."
systemctl restart netdata
systemctl enable netdata
# Wait for service to start
sleep 5
if systemctl is-active netdata >/dev/null 2>&1; then
log_info "Netdata service is running successfully"
else
log_error "Netdata service failed to start"
exit 1
fi
}
verify_installation() {
log_info "Verifying installation..."
# Check if Netdata is listening on port 19999
if netstat -tlnp 2>/dev/null | grep -q ":19999" || ss -tlnp 2>/dev/null | grep -q ":19999"; then
log_info "✓ Netdata web interface is accessible on port 19999"
else
log_warn "⚠ Netdata may not be listening on port 19999"
fi
# Check configuration files
if [[ -f "/etc/netdata/python.d/mysql.conf" ]]; then
log_info "✓ MySQL monitoring configuration is in place"
fi
if [[ -f "/etc/netdata/health.d/mysql_custom.conf" ]]; then
log_info "✓ Custom MySQL alerts configured"
fi
log_info "Installation completed successfully!"
log_info "Access Netdata dashboard at: http://$(hostname -I | awk '{print $1}'):19999"
log_info "MySQL monitoring will appear automatically once MySQL is detected"
}
main() {
if [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then
usage
fi
log_info "Starting Netdata MySQL monitoring setup..."
log_info "MySQL user: $MYSQL_USER"
log_info "Admin email: $ADMIN_EMAIL"
log_info "Network access: $NETWORK_RANGE"
check_prerequisites
detect_distro
update_system
install_netdata
configure_mysql_user
configure_netdata_mysql
configure_alerts
configure_notifications
configure_firewall
start_services
verify_installation
log_info "Setup completed! Monitor your MySQL database performance at http://$(hostname -I | awk '{print $1}'):19999"
}
main "$@"
Review the script before running. Execute with: bash install.sh