Using MySQL with QueryCanary

QueryCanary fully supports MySQL for production data monitoring. This guide walks you through connecting your database, writing SQL checks, and troubleshooting common issues.

Overview

QueryCanary connects directly to your MySQL database — with or without SSH tunneling — and allows you to define SQL checks to monitor important conditions in your data (e.g. low signups, null prices, broken joins).

You can:

  • Run scheduled SQL queries on your prod database
  • Set expectations or anomaly detection on results
  • Receive alerts via email or Slack when something looks off

Requirements

  • MySQL or MariaDB
  • A read-only database user
  • Access via direct TCP or through an SSH tunnel

We recommend connecting to a replica or using a read-only role for safety.

Setup

1. Create a Read-Only User

In your MySQL server, create a dedicated read-only user, grant it SELECT access to the database you want to monitor, and flush privileges to apply changes.

-- 1. Create a dedicated read-only user
CREATE USER 'querycanary_reader'@'%' IDENTIFIED BY 'your_secure_password';

-- 2. Grant read-only access to the database you want to monitor
GRANT SELECT ON your_database.* TO 'querycanary_reader'@'%';

-- 3. Flush privileges to apply changes
FLUSH PRIVILEGES;

Connecting to MySQL

Option 1: Direct Connection

Use this if your database is publicly accessible or hosted on a service like RDS, PlanetScale, or DigitalOcean.

You’ll need:

  • Hostname (for example, db.example.com)
  • Port (usually 3306)
  • Database name
  • Username and password

Option 2: SSH Tunnel (Recommended for Private Networks)

Use this if your database is in a private VPC and only accessible from a bastion host.

You’ll additionally need:

  • Bastion host (hostname or IP)
  • SSH username
  • SSH public key (we generate one for you securely)

QueryCanary connects via SSH, opens a secure tunnel, and connects to your internal MySQL instance.

Writing SQL Checks

You can monitor anything you can query. For example, you might check the number of daily signups by counting users created in the last day, or look for broken joins by counting orders without a matching user.

Daily Signups Check

SELECT COUNT(*) FROM users WHERE created_at >= CURDATE() - INTERVAL 1 DAY;

Broken Joins Check

SELECT COUNT(*) FROM orders o LEFT JOIN users u ON u.id = o.user_id WHERE u.id IS NULL;

Troubleshooting

If you can’t connect to the database, make sure the hostname and port are reachable, the user has SELECT permissions, and no VPN or firewall blocks our IP.

If the SSH tunnel fails, ensure your bastion host is reachable, the provided public key is added to authorized keys on the bastion, and the bastion user can access the database internally.

If a query fails or returns empty, test your query locally with the MySQL CLI or your app first. Avoid using LIMIT, ORDER BY, or formatting functions — QueryCanary only needs values. Use COUNT, SUM, AVG, or conditional expressions to track value changes.