Docker Container
Create an integration.json file and mount it as a volume:
[
{
"service": "mysql",
"monitor": true,
"host": "127.0.0.1",
"port": "3306",
"username": "watchlog_monitor",
"password": "your_password",
"database": []
}
]
database is only read by the legacy collector — the advanced one discovers every schema itself, so [] is correct.
Then run the container:
docker run -d \
--name watchlog-agent \
--network host \
-v /path/to/integration.json:/app/app/config/integration.json \
-e WATCHLOG_APIKEY="YOUR_APIKEY" \
-e WATCHLOG_SERVER="https://log.watchlog.io" \
watchlog/agent:latest
Reaching MySQL from the container
| MySQL runs… | Use |
|---|---|
On the same host, agent on --network host | 127.0.0.1 |
| On the same host, agent on a bridge network | host.docker.internal (Docker Desktop) or the host's LAN IP |
| In another container on a shared user-defined network | The container or service name, e.g. mysql |
| On a remote host | Its hostname or IP |
Grant host patterns
MySQL accounts are user and host. A user created as 'watchlog_monitor'@'localhost' will be rejected when the agent connects from a container, because from MySQL's perspective the connection arrives from the Docker bridge address. Create the account as @'%', or as the specific subnet.
If the agent and MySQL share a Docker network:
docker run -d \
--name watchlog-agent \
--network app-net \
-v /path/to/integration.json:/app/app/config/integration.json \
-e WATCHLOG_APIKEY="YOUR_APIKEY" \
-e WATCHLOG_SERVER="https://log.watchlog.io" \
watchlog/agent:latest
{
"service": "mysql",
"monitor": true,
"host": "mysql",
"port": "3306",
"username": "watchlog_monitor",
"password": "your_password",
"database": []
}
Creating the monitoring user
docker exec -i mysql mysql -uroot -p'root_password' <<'SQL'
CREATE USER IF NOT EXISTS 'watchlog_monitor'@'%' IDENTIFIED BY 'your_password';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'watchlog_monitor'@'%';
GRANT SELECT ON performance_schema.* TO 'watchlog_monitor'@'%';
GRANT SELECT ON information_schema.* TO 'watchlog_monitor'@'%';
FLUSH PRIVILEGES;
SQL
Tips
docker exec needs -i to attach stdin. Without it the heredoc is a silent no-op — the command appears to succeed and creates nothing.
performance_schema in the official image
The official mysql image ships with performance_schema = ON, so the Queries, Indexes and Locks tabs work out of the box. Confirm with:
docker exec -i mysql mysql -uwatchlog_monitor -p'your_password' \
-e "SHOW VARIABLES LIKE 'performance_schema'"
If a custom my.cnf is mounted, check it has not been disabled there.
Docker Compose
services:
watchlog-agent:
image: watchlog/agent:latest
container_name: watchlog-agent
restart: unless-stopped
environment:
WATCHLOG_APIKEY: "YOUR_APIKEY"
WATCHLOG_SERVER: "https://log.watchlog.io"
volumes:
- ./integration.json:/app/app/config/integration.json:ro
networks:
- app-net
networks:
app-net:
external: true
Multiple MySQL Instances
You can monitor multiple MySQL databases by adding multiple entries with the same service name. Each instance is automatically identified by its host:port combination.
[
{
"service": "mysql",
"monitor": true,
"host": "mysql-primary",
"port": "3306",
"username": "watchlog_monitor",
"password": "your_password",
"database": []
},
{
"service": "mysql",
"monitor": true,
"host": "mysql-replica",
"port": "3306",
"username": "watchlog_monitor",
"password": "your_password",
"database": []
}
]
Monitoring both sides of a replication pair is worth doing: the replica reports its own seconds behind source and thread state, which the primary cannot tell you.
MariaDB
The same configuration works — the agent detects MariaDB from the version string and switches to information_schema.innodb_lock_waits and the original replication terminology automatically.
