Set up comprehensive MySQL monitoring with Prometheus MySQL Exporter and Grafana dashboards. Track query performance, connections, replication lag, and resource usage with automated alerts for production database health.
Prerequisites
- MySQL server running
- Root access to server
- Basic familiarity with MySQL administration
- At least 2GB RAM available
What this solves
MySQL performance monitoring becomes critical as your database grows beyond basic development setups. Without proper metrics collection, you'll miss slow queries, connection pool exhaustion, replication lag, and resource bottlenecks until they cause outages. This tutorial sets up Prometheus MySQL Exporter to collect database metrics and configures Grafana dashboards with automated alerts for proactive 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 components.
sudo apt update && sudo apt upgrade -y
Create MySQL monitoring user
Create a dedicated MySQL user for the Prometheus exporter with minimal required privileges for security.
mysql -u root -p
Run these SQL commands to create the monitoring user and grant necessary permissions:
CREATE USER 'mysqld_exporter'@'localhost' IDENTIFIED BY 'StrongExporterPassword123!';
GRANT PROCESS, REPLICATION CLIENT ON . TO 'mysqld_exporter'@'localhost';
GRANT SELECT ON performance_schema.* TO 'mysqld_exporter'@'localhost';
GRANT SELECT ON information_schema.* TO 'mysqld_exporter'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Install MySQL Exporter
Download and install the latest MySQL Exporter binary from the official GitHub releases.
cd /tmp
wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.15.1/mysqld_exporter-0.15.1.linux-amd64.tar.gz
tar xzf mysqld_exporter-0.15.1.linux-amd64.tar.gz
sudo mv mysqld_exporter-0.15.1.linux-amd64/mysqld_exporter /usr/local/bin/
sudo chmod +x /usr/local/bin/mysqld_exporter
Create MySQL Exporter user and directories
Create a system user and directories for the MySQL Exporter service with proper security isolation.
sudo useradd --no-create-home --shell /bin/false mysqld_exporter
sudo mkdir -p /etc/mysqld_exporter
sudo chown mysqld_exporter:mysqld_exporter /etc/mysqld_exporter
Configure MySQL Exporter credentials
Create a secure configuration file with MySQL connection details for the exporter.
[client]
host=localhost
port=3306
user=mysqld_exporter
password=StrongExporterPassword123!
Set proper permissions to protect the credentials file:
sudo chown mysqld_exporter:mysqld_exporter /etc/mysqld_exporter/.my.cnf
sudo chmod 600 /etc/mysqld_exporter/.my.cnf
Create MySQL Exporter systemd service
Configure MySQL Exporter as a systemd service for automatic startup and proper process management.
[Unit]
Description=MySQL Exporter
Wants=network-online.target
After=network-online.target
[Service]
User=mysqld_exporter
Group=mysqld_exporter
Type=simple
ExecStart=/usr/local/bin/mysqld_exporter --config.my-cnf=/etc/mysqld_exporter/.my.cnf --collect.global_status --collect.info_schema.innodb_metrics --collect.auto_increment.columns --collect.info_schema.processlist --collect.binlog_size --collect.info_schema.tablestats --collect.global_variables --collect.info_schema.query_response_time --collect.info_schema.userstats --collect.info_schema.tables --collect.perf_schema.tablelocks --collect.perf_schema.file_events --collect.perf_schema.eventswaits --collect.perf_schema.indexiowaits --collect.perf_schema.tableiowaits --collect.slave_status --web.listen-address=0.0.0.0:9104
Restart=always
[Install]
WantedBy=multi-user.target
Start and enable MySQL Exporter
Enable the MySQL Exporter service to start on boot and verify it's running correctly.
sudo systemctl daemon-reload
sudo systemctl enable --now mysqld_exporter
sudo systemctl status mysqld_exporter
Install Prometheus
Install Prometheus to collect metrics from the MySQL Exporter and other system components.
cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v2.47.2/prometheus-2.47.2.linux-amd64.tar.gz
tar xzf prometheus-2.47.2.linux-amd64.tar.gz
sudo mv prometheus-2.47.2.linux-amd64/prometheus /usr/local/bin/
sudo mv prometheus-2.47.2.linux-amd64/promtool /usr/local/bin/
sudo chmod +x /usr/local/bin/prometheus /usr/local/bin/promtool
Create Prometheus user and directories
Set up dedicated user and directories for Prometheus with proper permissions for data storage and configuration.
sudo useradd --no-create-home --shell /bin/false prometheus
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /etc/prometheus /var/lib/prometheus
Configure Prometheus to scrape MySQL metrics
Create Prometheus configuration to collect metrics from MySQL Exporter and system node exporter.
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "/etc/prometheus/mysql_rules.yml"
alerting:
alertmanagers:
- static_configs:
- targets:
- localhost:9093
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'mysql'
static_configs:
- targets: ['localhost:9104']
scrape_interval: 5s
metrics_path: /metrics
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
Set proper ownership for the configuration file:
sudo chown prometheus:prometheus /etc/prometheus/prometheus.yml
Create MySQL alerting rules
Define alert rules for common MySQL performance and availability issues.
groups:
- name: mysql_alerts
rules:
- alert: MySQLDown
expr: mysql_up == 0
for: 0m
labels:
severity: critical
annotations:
summary: "MySQL instance is down"
description: "MySQL database is down on {{ $labels.instance }}"
- alert: MySQLTooManyConnections
expr: max_over_time(mysql_global_status_threads_connected[1m]) / mysql_global_variables_max_connections * 100 > 80
for: 2m
labels:
severity: warning
annotations:
summary: "MySQL connection usage is high"
description: "More than 80% of MySQL connections are in use on {{ $labels.instance }}"
- alert: MySQLHighQPS
expr: rate(mysql_global_status_questions[5m]) > 1000
for: 2m
labels:
severity: warning
annotations:
summary: "MySQL high queries per second"
description: "MySQL is executing {{ $value }} queries per second on {{ $labels.instance }}"
- alert: MySQLSlowQueries
expr: increase(mysql_global_status_slow_queries[1m]) > 0
for: 2m
labels:
severity: warning
annotations:
summary: "MySQL slow queries detected"
description: "MySQL has {{ $value }} slow queries in the last minute on {{ $labels.instance }}"
- alert: MySQLInnoDBLogWaits
expr: rate(mysql_global_status_innodb_log_waits[15m]) > 10
for: 0m
labels:
severity: warning
annotations:
summary: "MySQL InnoDB log writes are stalling"
description: "MySQL InnoDB log writes are waiting for disk at a rate of {{ $value }} per second on {{ $labels.instance }}"
- alert: MySQLReplicationLag
expr: mysql_slave_lag_seconds > 30
for: 1m
labels:
severity: critical
annotations:
summary: "MySQL replication lag is high"
description: "MySQL slave is {{ $value }} seconds behind master on {{ $labels.instance }}"
- alert: MySQLReplicationSQLThreadNotRunning
expr: mysql_slave_sql_running == 0
for: 0m
labels:
severity: critical
annotations:
summary: "MySQL replication SQL thread is not running"
description: "MySQL replication SQL thread is not running on {{ $labels.instance }}"
- alert: MySQLReplicationIOThreadNotRunning
expr: mysql_slave_io_running == 0
for: 0m
labels:
severity: critical
annotations:
summary: "MySQL replication IO thread is not running"
description: "MySQL replication IO thread is not running on {{ $labels.instance }}"
- alert: MySQLTableLockWaitsHigh
expr: rate(mysql_global_status_table_locks_waited[15m]) / rate(mysql_global_status_table_locks_immediate[15m]) > 0.02
for: 1m
labels:
severity: warning
annotations:
summary: "MySQL table lock waits are high"
description: "MySQL table lock wait rate is {{ $value }} on {{ $labels.instance }}"
- alert: MySQLInnoDBBufferPoolEfficiency
expr: mysql_global_status_innodb_buffer_pool_reads / mysql_global_status_innodb_buffer_pool_read_requests > 0.02
for: 5m
labels:
severity: warning
annotations:
summary: "MySQL InnoDB buffer pool efficiency is low"
description: "MySQL InnoDB buffer pool read miss ratio is {{ $value }} on {{ $labels.instance }}"
Set ownership for the rules file:
sudo chown prometheus:prometheus /etc/prometheus/mysql_rules.yml
Install Node Exporter for system metrics
Install Node Exporter to collect system-level metrics that complement MySQL monitoring.
cd /tmp
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz
tar xzf node_exporter-1.6.1.linux-amd64.tar.gz
sudo mv node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/
sudo chmod +x /usr/local/bin/node_exporter
Create Node Exporter systemd service
Configure Node Exporter as a systemd service for system metrics collection.
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter --web.listen-address=0.0.0.0:9100
Restart=always
[Install]
WantedBy=multi-user.target
Create the node_exporter user and start the service:
sudo useradd --no-create-home --shell /bin/false node_exporter
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
Create Prometheus systemd service
Configure Prometheus as a systemd service for metrics collection and alerting.
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus \
--config.file /etc/prometheus/prometheus.yml \
--storage.tsdb.path /var/lib/prometheus/ \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries \
--web.listen-address=0.0.0.0:9090 \
--web.enable-lifecycle \
--storage.tsdb.retention.time=15d
Restart=always
[Install]
WantedBy=multi-user.target
Start Prometheus service
Enable and start Prometheus to begin collecting MySQL and system metrics.
sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
sudo systemctl status prometheus
Install Grafana
Install Grafana for visualizing MySQL performance metrics with professional dashboards.
sudo apt install -y software-properties-common
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y grafana
Configure Grafana
Configure basic Grafana settings for security and MySQL monitoring integration.
[server]
http_addr = 0.0.0.0
http_port = 3000
domain = example.com
root_url = http://example.com:3000/
[security]
admin_user = admin
admin_password = StrongGrafanaPassword123!
secret_key = SW2YcwTIb9zpOOhoPsMm
[users]
allow_sign_up = false
default_theme = dark
[auth.anonymous]
enabled = false
[log]
mode = console file
level = info
Start Grafana service
Enable and start Grafana for web-based MySQL performance visualization.
sudo systemctl enable --now grafana-server
sudo systemctl status grafana-server
Configure firewall rules
Open necessary ports for Prometheus, Grafana, and MySQL Exporter access.
sudo ufw allow 3000/tcp
sudo ufw allow 9090/tcp
sudo ufw allow 9104/tcp
sudo ufw allow 9100/tcp
Add Prometheus data source to Grafana
Configure Grafana to use Prometheus as a data source for MySQL metrics visualization.
Access Grafana at http://your-server-ip:3000 and log in with your admin credentials. Then add the data source:
curl -X POST \
http://admin:StrongGrafanaPassword123!@localhost:3000/api/datasources \
-H 'Content-Type: application/json' \
-d '{
"name":"Prometheus",
"type":"prometheus",
"url":"http://localhost:9090",
"access":"proxy",
"isDefault":true
}'
Import MySQL dashboard
Import a comprehensive MySQL dashboard template for immediate performance monitoring visualization.
curl -X POST \
http://admin:StrongGrafanaPassword123!@localhost:3000/api/dashboards/import \
-H 'Content-Type: application/json' \
-d '{
"dashboard": {
"id": null,
"title": "MySQL Performance Dashboard",
"tags": ["mysql", "prometheus"],
"timezone": "browser",
"panels": [
{
"id": 1,
"title": "MySQL Status",
"type": "stat",
"targets": [{
"expr": "mysql_up",
"refId": "A"
}],
"gridPos": {"h": 4, "w": 6, "x": 0, "y": 0}
},
{
"id": 2,
"title": "Connections",
"type": "timeseries",
"targets": [{
"expr": "mysql_global_status_threads_connected",
"refId": "A",
"legendFormat": "Connected"
}, {
"expr": "mysql_global_variables_max_connections",
"refId": "B",
"legendFormat": "Max Connections"
}],
"gridPos": {"h": 8, "w": 12, "x": 6, "y": 0}
},
{
"id": 3,
"title": "Queries Per Second",
"type": "timeseries",
"targets": [{
"expr": "rate(mysql_global_status_questions[5m])",
"refId": "A",
"legendFormat": "QPS"
}],
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 8}
},
{
"id": 4,
"title": "InnoDB Buffer Pool Usage",
"type": "timeseries",
"targets": [{
"expr": "mysql_global_status_innodb_buffer_pool_pages_data / mysql_global_status_innodb_buffer_pool_pages_total * 100",
"refId": "A",
"legendFormat": "Buffer Pool Usage %"
}],
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 8}
},
{
"id": 5,
"title": "Slow Queries",
"type": "timeseries",
"targets": [{
"expr": "rate(mysql_global_status_slow_queries[5m])",
"refId": "A",
"legendFormat": "Slow Queries/sec"
}],
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 16}
},
{
"id": 6,
"title": "MySQL Uptime",
"type": "stat",
"targets": [{
"expr": "mysql_global_status_uptime",
"refId": "A"
}],
"gridPos": {"h": 4, "w": 6, "x": 12, "y": 16}
}
],
"time": {
"from": "now-1h",
"to": "now"
},
"refresh": "5s"
}
}'
Install Alertmanager for notifications
Install and configure Alertmanager to handle alert notifications from Prometheus MySQL rules.
cd /tmp
wget https://github.com/prometheus/alertmanager/releases/download/v0.26.0/alertmanager-0.26.0.linux-amd64.tar.gz
tar xzf alertmanager-0.26.0.linux-amd64.tar.gz
sudo mv alertmanager-0.26.0.linux-amd64/alertmanager /usr/local/bin/
sudo mv alertmanager-0.26.0.linux-amd64/amtool /usr/local/bin/
sudo chmod +x /usr/local/bin/alertmanager /usr/local/bin/amtool
Configure Alertmanager
Set up Alertmanager with email notifications for MySQL performance alerts.
sudo useradd --no-create-home --shell /bin/false alertmanager
sudo mkdir -p /etc/alertmanager /var/lib/alertmanager
sudo chown alertmanager:alertmanager /etc/alertmanager /var/lib/alertmanager
global:
smtp_smarthost: 'localhost:587'
smtp_from: 'alerts@example.com'
smtp_auth_username: 'alerts@example.com'
smtp_auth_password: 'your_email_password'
smtp_require_tls: true
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 1h
receiver: 'web.hook'
receivers:
- name: 'web.hook'
email_configs:
- to: 'admin@example.com'
subject: 'MySQL Alert: {{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'
body: |
{{ range .Alerts }}
Alert: {{ .Annotations.summary }}
Description: {{ .Annotations.description }}
Instance: {{ .Labels.instance }}
Severity: {{ .Labels.severity }}
{{ end }}
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'dev', 'instance']
Set proper ownership:
sudo chown alertmanager:alertmanager /etc/alertmanager/alertmanager.yml
Create Alertmanager systemd service
Configure Alertmanager as a systemd service for reliable alert processing and notification delivery.
[Unit]
Description=Alertmanager
Wants=network-online.target
After=network-online.target
[Service]
User=alertmanager
Group=alertmanager
Type=simple
ExecStart=/usr/local/bin/alertmanager \
--config.file /etc/alertmanager/alertmanager.yml \
--storage.path /var/lib/alertmanager/ \
--web.listen-address=0.0.0.0:9093
Restart=always
[Install]
WantedBy=multi-user.target
Start the Alertmanager service:
sudo systemctl daemon-reload
sudo systemctl enable --now alertmanager
sudo systemctl status alertmanager
Configure Grafana dashboards
Access Grafana web interface
Open your web browser and navigate to Grafana to complete the dashboard setup for MySQL monitoring.
Visit http://your-server-ip:3000 and log in with username admin and the password you configured.
Create custom MySQL performance dashboard
Build comprehensive dashboards for different aspects of MySQL performance monitoring.
In Grafana, create new dashboards with these key panels:
- MySQL Status Panel:
mysql_up- Shows if MySQL is running - Connection Usage:
(mysql_global_status_threads_connected / mysql_global_variables_max_connections) * 100 - Query Performance:
rate(mysql_global_status_questions[5m]) - Slow Query Rate:
rate(mysql_global_status_slow_queries[5m]) - InnoDB Buffer Pool Efficiency:
(1 - mysql_global_status_innodb_buffer_pool_reads / mysql_global_status_innodb_buffer_pool_read_requests) * 100 - Table Locks:
rate(mysql_global_status_table_locks_waited[5m]) - Replication Lag:
mysql_slave_lag_seconds(if using replication)
Set up alert notifications in Grafana
Configure Grafana alerts to complement Prometheus alerting for comprehensive MySQL monitoring coverage.
Create notification channels in Grafana for:
- Email notifications for critical MySQL issues
- Slack integration for team alerts
- Webhook notifications for automated responses
Verify your setup
Test all components of your MySQL monitoring stack to ensure proper data collection and alerting.
# Check MySQL Exporter metrics
curl http://localhost:9104/metrics | grep mysql_up
Verify Prometheus is collecting MySQL metrics
curl http://localhost:9090/api/v1/query?query=mysql_up
Test Prometheus rules
prometheus-tool query mysql_global_status_threads_connected
Check Grafana API
curl -u admin:StrongGrafanaPassword123! http://localhost:3000/api/health
Verify all services are running
sudo systemctl status mysqld_exporter prometheus node_exporter grafana-server alertmanager
Access your monitoring interfaces:
- Prometheus:
http://your-server-ip:9090 - Grafana:
http://your-server-ip:3000 - Alertmanager:
http://your-server-ip:9093 - MySQL Exporter metrics:
http://your-server-ip:9104/metrics
Common issues
| Symptom | Cause | Fix |
|---|---|---|
MySQL Exporter shows mysql_up 0 |
MySQL connection failed or wrong credentials | Check MySQL user permissions and password in /etc/mysqld_exporter/.my.cnf |
| No data in Grafana dashboards | Prometheus not scraping MySQL Exporter | Verify prometheus.yml targets and check http://localhost:9090/targets |
| Permission denied errors | Incorrect file ownership or permissions | Run sudo chown mysqld_exporter:mysqld_exporter /etc/mysqld_exporter/.my.cnf |
| Alerts not firing | Alert rules not loaded or thresholds too high | Check Prometheus rules with promtool check rules /etc/prometheus/mysql_rules.yml |
| Grafana cannot connect to Prometheus | Prometheus not running or wrong URL | Verify Prometheus is running on port 9090 and check data source URL |
| Email alerts not working | SMTP configuration incorrect | Test SMTP settings and check Alertmanager logs with journalctl -u alertmanager |
| High memory usage by Prometheus | Too many metrics or long retention | Adjust --storage.tsdb.retention.time or filter metrics in scrape configs |
| Missing InnoDB metrics | MySQL Exporter collectors not enabled | Add --collect.info_schema.innodb_metrics to exporter service |
Next steps
- Implement MySQL backup automation with Percona XtraBackup for comprehensive database protection
- Set up MySQL replication with GTID and automatic failover for high availability
- Configure Linux filesystem tuning for database workloads to optimize MySQL performance
- Configure MySQL slow query optimization and performance tuning for better query performance
- Set up MySQL Galera cluster monitoring with Prometheus for multi-master setups
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Variables
MYSQL_EXPORTER_VERSION="0.15.1"
PROMETHEUS_VERSION="2.47.2"
GRAFANA_VERSION="10.2.0"
MYSQL_EXPORTER_PASSWORD="${MYSQL_EXPORTER_PASSWORD:-StrongExporterPassword$(date +%s)!}"
MYSQL_ROOT_PASSWORD=""
# Functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
cleanup() {
log_error "Installation failed. Cleaning up..."
systemctl stop mysqld_exporter 2>/dev/null || true
systemctl stop prometheus 2>/dev/null || true
systemctl stop grafana-server 2>/dev/null || true
userdel -r mysqld_exporter 2>/dev/null || true
userdel -r prometheus 2>/dev/null || true
rm -rf /etc/mysqld_exporter /etc/prometheus /usr/local/bin/mysqld_exporter /usr/local/bin/prometheus 2>/dev/null || true
}
trap cleanup ERR
usage() {
echo "Usage: $0 [mysql_root_password]"
echo " mysql_root_password: MySQL root password (will prompt if not provided)"
exit 1
}
check_prerequisites() {
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root"
exit 1
fi
if ! command -v mysql &> /dev/null; then
log_error "MySQL/MariaDB is not installed. Please install it first."
exit 1
fi
}
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
FIREWALL_CMD="ufw"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
FIREWALL_CMD="firewall-cmd"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
FIREWALL_CMD="firewall-cmd"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution"
exit 1
fi
}
# Main installation
main() {
if [[ $# -gt 1 ]]; then
usage
fi
if [[ $# -eq 1 ]]; then
MYSQL_ROOT_PASSWORD="$1"
else
read -s -p "Enter MySQL root password: " MYSQL_ROOT_PASSWORD
echo
fi
check_prerequisites
detect_distro
log_info "[1/10] Updating system packages..."
eval $PKG_UPDATE
log_info "[2/10] Installing dependencies..."
$PKG_INSTALL wget tar curl
log_info "[3/10] Creating MySQL monitoring user..."
mysql -u root -p"$MYSQL_ROOT_PASSWORD" -e "
CREATE USER IF NOT EXISTS 'mysqld_exporter'@'localhost' IDENTIFIED BY '$MYSQL_EXPORTER_PASSWORD';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'mysqld_exporter'@'localhost';
GRANT SELECT ON performance_schema.* TO 'mysqld_exporter'@'localhost';
GRANT SELECT ON information_schema.* TO 'mysqld_exporter'@'localhost';
FLUSH PRIVILEGES;"
log_info "[4/10] Installing MySQL Exporter..."
cd /tmp
wget -q "https://github.com/prometheus/mysqld_exporter/releases/download/v${MYSQL_EXPORTER_VERSION}/mysqld_exporter-${MYSQL_EXPORTER_VERSION}.linux-amd64.tar.gz"
tar xzf "mysqld_exporter-${MYSQL_EXPORTER_VERSION}.linux-amd64.tar.gz"
mv "mysqld_exporter-${MYSQL_EXPORTER_VERSION}.linux-amd64/mysqld_exporter" /usr/local/bin/
chmod 755 /usr/local/bin/mysqld_exporter
log_info "[5/10] Configuring MySQL Exporter..."
useradd --no-create-home --shell /bin/false mysqld_exporter || true
mkdir -p /etc/mysqld_exporter
chown mysqld_exporter:mysqld_exporter /etc/mysqld_exporter
chmod 755 /etc/mysqld_exporter
cat > /etc/mysqld_exporter/.my.cnf << EOF
[client]
host=localhost
port=3306
user=mysqld_exporter
password=$MYSQL_EXPORTER_PASSWORD
EOF
chown mysqld_exporter:mysqld_exporter /etc/mysqld_exporter/.my.cnf
chmod 600 /etc/mysqld_exporter/.my.cnf
cat > /etc/systemd/system/mysqld_exporter.service << 'EOF'
[Unit]
Description=MySQL Exporter
Wants=network-online.target
After=network-online.target
[Service]
User=mysqld_exporter
Group=mysqld_exporter
Type=simple
ExecStart=/usr/local/bin/mysqld_exporter --config.my-cnf=/etc/mysqld_exporter/.my.cnf --collect.global_status --collect.info_schema.innodb_metrics --collect.auto_increment.columns --collect.info_schema.processlist --collect.binlog_size --collect.info_schema.tablestats --collect.global_variables --collect.slave_status --web.listen-address=0.0.0.0:9104
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now mysqld_exporter
log_info "[6/10] Installing Prometheus..."
wget -q "https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz"
tar xzf "prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz"
mv "prometheus-${PROMETHEUS_VERSION}.linux-amd64/prometheus" /usr/local/bin/
chmod 755 /usr/local/bin/prometheus
useradd --no-create-home --shell /bin/false prometheus || true
mkdir -p /etc/prometheus /var/lib/prometheus
chown prometheus:prometheus /etc/prometheus /var/lib/prometheus
chmod 755 /etc/prometheus /var/lib/prometheus
cat > /etc/prometheus/prometheus.yml << 'EOF'
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'mysql'
static_configs:
- targets: ['localhost:9104']
EOF
chown prometheus:prometheus /etc/prometheus/prometheus.yml
chmod 644 /etc/prometheus/prometheus.yml
cat > /etc/systemd/system/prometheus.service << 'EOF'
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/var/lib/prometheus/ --web.console.templates=/etc/prometheus/consoles --web.console.libraries=/etc/prometheus/console_libraries --web.listen-address=0.0.0.0:9090
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now prometheus
log_info "[7/10] Installing Grafana..."
if [[ "$PKG_MGR" == "apt" ]]; then
$PKG_INSTALL software-properties-common
wget -q -O - https://packages.grafana.com/gpg.key | apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" > /etc/apt/sources.list.d/grafana.list
apt update
$PKG_INSTALL grafana
else
cat > /etc/yum.repos.d/grafana.repo << 'EOF'
[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
EOF
$PKG_INSTALL grafana
fi
systemctl enable --now grafana-server
log_info "[8/10] Configuring firewall..."
if command -v ufw &> /dev/null; then
ufw --force enable 2>/dev/null || true
ufw allow 3000/tcp comment "Grafana" || true
ufw allow 9090/tcp comment "Prometheus" || true
elif command -v firewall-cmd &> /dev/null; then
systemctl enable --now firewalld 2>/dev/null || true
firewall-cmd --permanent --add-port=3000/tcp --add-port=9090/tcp 2>/dev/null || true
firewall-cmd --reload 2>/dev/null || true
fi
log_info "[9/10] Waiting for services to start..."
sleep 10
log_info "[10/10] Verifying installation..."
if systemctl is-active --quiet mysqld_exporter && \
systemctl is-active --quiet prometheus && \
systemctl is-active --quiet grafana-server && \
curl -s http://localhost:9104/metrics | grep -q mysql && \
curl -s http://localhost:9090/-/healthy | grep -q "Prometheus is Healthy"; then
log_info "Installation completed successfully!"
echo ""
echo "Access URLs:"
echo " Grafana: http://$(hostname -I | awk '{print $1}'):3000 (admin/admin)"
echo " Prometheus: http://$(hostname -I | awk '{print $1}'):9090"
echo " MySQL Exporter: http://$(hostname -I | awk '{print $1}'):9104/metrics"
echo ""
echo "MySQL Exporter Password: $MYSQL_EXPORTER_PASSWORD"
echo "Save this password for future reference!"
else
log_error "Service verification failed. Check logs with: journalctl -u mysqld_exporter -u prometheus -u grafana-server"
exit 1
fi
}
main "$@"
Review the script before running. Execute with: bash install.sh