Using PostgreSQL with QueryCanary

QueryCanary fully supports PostgreSQL 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 PostgreSQL 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

  • PostgreSQL version 10 or higher
  • 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 Postgres server:

-- 1. Create a dedicated read-only user
CREATE USER querycanary_reader WITH PASSWORD 'your_secure_password';

-- 2. Allow it to connect to your database
GRANT CONNECT ON DATABASE your_database TO querycanary_reader;

-- 3. Grant usage on the schema you want to monitor (typically public)
GRANT USAGE ON SCHEMA public TO querycanary_reader;

-- 4. Grant read-only access to all existing tables
GRANT SELECT ON ALL TABLES IN SCHEMA public TO querycanary_reader;

-- 5. Ensure access to future tables too
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO querycanary_reader;

Connecting to Postgres

Option 1: Direct Connection

Use this if your database is publicly accessible or hosted on a service like RDS, Supabase, or Fly.io.

You’ll need:

  • Hostname (e.g. db.example.com)
  • Port (usually 5432)
  • Database name
  • Username & password

Option 2: SSH Tunnel (Recommended for Private Networks)

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

You’ll additionally need:

  • Bastion host (hostname/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 Postgres instance.

Writing SQL Checks

You can monitor anything you can query. Example:

Daily Signups Check

SELECT COUNT(*) FROM users WHERE created_at >= CURRENT_DATE - 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

Can’t connect to database

  • Make sure the hostname and port are reachable
  • Check that the user has CONNECT and SELECT permissions
  • Confirm no VPN/firewall blocks our IP (contact support if needed)

SSH tunnel fails

  • Make sure your bastion host is reachable
  • Add the provided public key to ~/.ssh/authorized_keys on the bastion
  • Check that the bastion user can access the database internally

Query fails or returns empty

  • Test your query locally with psql or your app first
  • Avoid LIMIT, ORDER BY, or formatting functions — we only need values
  • Use COUNT, SUM, AVG, or conditional expressions to track value changes