Skip to content
Rowsafe
Docs

Pulse: monitoring and alerts

Health score, one-click fixes, alerts, the weekly email, and alerts by email, Slack, Discord, Microsoft Teams, PagerDuty, Opsgenie, Telegram, ntfy or webhook.

Pulse watches your databases with nothing to set up. It gives each a health score, findings, graphs, alerts, slow queries and a Monday email. Most problems come with Apply fix.

It starts when you add a database, on every plan. This page shows PostgreSQL; see By database for the others.

What the agent collects

Every 60 seconds the agent runs a few cheap catalog queries (session rowsafe-agent-monitor, Unix socket, 2-second timeout). A struggling server shows a gap, never a pile-up. Monitoring never blocks a backup, Proof or Mark.

Privacy

  • pg_stat_statements text is normalized: values become $1, $2. So are query plans.
  • Activity query text is not. It can hold personal data. ROWSAFE_COLLECT_QUERY_TEXT=false in /etc/rowsafe/agent.env leaves it out.
  • Statements that look like they carry a password are redacted on your server.
  • ROWSAFE_MONITORING=false turns monitoring off (heartbeats and task results only).
  • The database's own log is separate: Logs.

Retention

ResolutionKept for
1 minute48 hours
5 minutes14 days
1 hour90 days

Resolved alerts: 90 days. Sent notifications: 30 days.

By database

Score, alerts, uptime, disk forecast, slow queries and the weekly email work for every engine. Values are removed from statements on your server.

What Pulse watchesOne-click fixes
MySQL, MariaDBconnections, queries per second, slow queries (performance_schema), row lock waits, the buffer pool, long transactions, replication delaystop a query or end a blocking session, rebuild a table with a lot of free space (OPTIMIZE TABLE), turn on the slow query log
MongoDBconnections, operations, queues, the WiredTiger cache, write conflicts, the oplog window, secondary lag, slow operations (the profiler)stop an operation (killOp), turn on query statistics
ClickHousequeries, inserts, merges, memory, data parts per partition, mutations, replication, broken parts, the queries running nowstop a query (KILL QUERY), cancel a stuck mutation (KILL MUTATION)
OpenSearchcluster health, shards, disk against OpenSearch's watermarks, read-only indices, heap and garbage collection, refused requests, the last snapshotset replicas to 0 on one node, allow writes again once the disk has room (details)
Qdrantmemory, collections and their status, the issues Qdrant reports (like unindexed fields), snapshots left on disk, keyscreate the index Qdrant suggests, move a collection's vectors to disk, remove admin keys (details)
Meilisearchsize on disk and what the data uses, indexes, the task queue (waiting, failed), the indexing memory limitcompact an index, clear old finished tasks (details)
Redis, Valkeymemory against maxmemory, evictions, hit rate, commands per second, clients (blocked, rejected), fragmentation, persistence, replication and lag, the slow log (command names only), latency events; a server without a password is flaggedset an eviction policy, give memory back (MEMORY PURGE) or turn on active defragmentation, disconnect a stuck client, raise the replication backlog

All also get: back up now, Restart, updates, security updates and reboots, Tune for this server, and Recommendations' index changes. Redis and Valkey don't have updates, tuning or Recommendations yet (details). More: MySQL and MariaDB, MongoDB, ClickHouse.

Health score

Each database gets a score from 0 to 100 and its findings, worst first: what's wrong, why it matters, what to do, and a button when Rowsafe can do it.

ScoreMeaning
90-100Healthy
70-89Needs attention
50-69At risk
Under 50Critical

Points come off for backups and Proof, availability, disk, connections, vacuum and wraparound, locks and slow queries, replication, and security (up to 25).

  • One critical problem caps the score at 59, a warning at 89. A good score never hides a serious problem.
  • Missing data means fewer findings, never a false alarm.
  • Recorded every 15 minutes, so you see the trend.
rowsafe pulse          # every database, worst first
rowsafe pulse app      # one database: score, findings, and what's fine

rowsafe pulse exits with code 3 when a database scores below 70.

Apply fix

Fix buttons appear under Pulse → Health, and next to the same problem on Insights, Monitoring, Queries and Alerts. Click, confirm if asked, and watch each step and the result ("Cleaned up 3 tables; about 1.2 million dead rows removed.").

ProblemButtonWhat Rowsafe does
No backup yet, or the last one is too oldBack up nowStarts a full backup.
The latest Proof failed, or none passed this weekRun Proof nowRuns a restore test.
Backups can't reach your storageCheck againTests that changes reach your bucket, once you've fixed the reported problem.
Backups aren't on yetTurn on backupsApplies the setup plan (after you confirm).
PostgreSQL is waiting for a restartRestart PostgreSQL nowRestarts it, where restarts are allowed.
Backups can be up to 5 minutes behindApply fixSets archive_timeout to a minute. A reload, no restart.
A Rewind copy is about to expireKeep it 24 hours longerKeeps the copy 24 more hours.
Data kept aside by a rewind uses diskDelete the old data nowDeletes the data from before the rewind. Can't be undone.
Dead rows piling up, vacuum behind, transaction or multixact ID wraparoundClean upVACUUM (ANALYZE) on those tables, with FREEZE for wraparound.
Cleanup is blocked: something holds old rows that VACUUM can't removeOne button per blockerEnds the old session (or cancels its query), rolls back a forgotten prepared transaction, removes an inactive replication slot or moves a logical one forward. You confirm each. A standby's queries: under Do it yourself.
Every autovacuum worker is busy for 30 minutesGive cleanup more roomRaises autovacuum_vacuum_cost_limit at once and autovacuum_max_workers by 2. Before PostgreSQL 18, the extra workers need a restart, which you choose when.
A query got slowerRefresh statisticsANALYZE on the tables it reads, when their statistics may be stale, then checks again. Otherwise (or for inserts) it shows the likely causes.
An index with a lot of wasted spaceRebuild indexREINDEX INDEX CONCURRENTLY (PostgreSQL 12 and later).
A table with a lot of wasted space, where pg_repack is installedRebuild (pg_repack)Rebuilds the table while your app keeps working (a short lock at the start and end), after a Mark. Needs a primary key and free disk for the copy.
An unused or duplicate indexRemoveDROP INDEX CONCURRENTLY, after saving a Mark.
An index would make slow queries faster (tested on a copy)Create indexCREATE INDEX CONCURRENTLY; a failed build leaves nothing behind.
The hypopg package is installed but offTurn on hypopgCREATE EXTENSION hypopg, so index ideas are checked without a copy first. Tables and data don't change.
A session idle in a transaction, a transaction open too long, a session blocking othersEnd this session, or cancel its querypg_terminate_backend, or pg_cancel_backend for a running query.
An inactive replication slot holding back WALRemove the slotpg_drop_replication_slot.
Most connections are in use, or almost none are leftTurn on poolingInstalls and starts PgBouncer, where allowed. See Connection pooling.
PgBouncer isn't answeringStart PgBouncer againRewrites its configuration and starts it.
Apps wait for a connection in PgBouncerRaise the pool size, or Switch to transaction modeRaises the pool by half, within max_connections, or switches to transaction mode. Nothing is disconnected.
Some changes didn't reach the second copy, or it has no full backupBack up to the second copyA full backup into the second copy.
Keeping one full backup fewer would save money, safelyKeep 1 full backupChanges the setting; the oldest full backup goes at the next backup (after you confirm).
The disk is filling upThe fixes above that free spaceRemoving an inactive slot or unused indexes, cleaning up tables.
PostgreSQL uses default memory settings on a bigger serverTune for this serverApplies the recommended settings, after a Mark. See Tuning.
Query statistics are off (pg_stat_statements isn't loaded)Turn on query statisticsAdds it to shared_preload_libraries and creates the extension; it starts after the next restart.
Changed settings wait for a restartRestart PostgreSQLRestarts it, where restarts are allowed.
A newer PostgreSQL minor release is availableUpdate to 16.10A Mark, the install, a restart, where updates are allowed. See Updates.
A newer release is installed but not running yetRestart PostgreSQLRestarts it, where restarts are allowed.
Security updates are waitingInstall security updatesA Mark, then the server's security updates (not PostgreSQL's packages), where allowed.
The server needs a rebootReboot the serverA Mark, then a reboot (you type the name), where allowed.
An upgrade keeps the old PostgreSQL versionRemove PostgreSQL 16Deletes the version kept for undo, freeing its disk.
Connections aren't encrypted, weak password hashing, CREATE on schema public for everyoneTurn on encryption, Use modern password hashing, Remove CREATE from everyoneSee the security check.

Pulse also warns when your major version stops getting security fixes, or will within six months. Upgrading starts with a check and a rehearsal on the Updates tab (how).

No button for (the finding explains, with commands under Do it yourself): an offline agent, storage keys (they never leave your server), an untested index (only foreign-key indexes and indexes proven on a copy are created), a full table rebuild without pg_repack on the server (VACUUM FULL), your own PgBouncer, and replication lag.

What keeps it safe

  • Only Rowsafe's own fixes. You pick a finding and a fix; Rowsafe rechecks and runs that exact fix with its own parameters. No SQL is sent.
  • Rechecked on the server just before running: the table, index, session or slot is still the one found. Rowsafe, replication and autovacuum sessions are never ended. Indexes behind a primary key, unique or exclusion constraint are never removed.
  • Owners and admins only. Read-only API keys can't apply fixes. Every fix is audited.
  • You confirm what disrupts. Ending a session or removing an index or slot asks you to type the database name.
  • A Mark first (before-fix-...) before removing an index, so you can restore to just before it.
  • Gentle. Index changes wait at most 5 seconds for a lock, run CONCURRENTLY, and vacuum runs with a cost delay. One fix at a time per database.
  • AI agents apply fixes with apply_fix on the MCP server, as the person who connected them: at once for an owner or admin, refused otherwise.

Restart now or later

Some fixes and settings only take effect after a restart: a few seconds of refused connections. Restart (on the database's page, or the fix) asks when:

  • Now.
  • Later: a time you pick, up to 30 days ahead.
  • In the next maintenance window, on Rowsafe Cloud.

You confirm with the database's name. A banner on the database's page shows the scheduled restart, with Cancel. The addresses that get your weekly Pulse get an email when it's scheduled, an hour before, and after.

At that time Rowsafe restarts it like Restart now, only where root allowed restarts. If the server isn't reporting, it keeps trying for an hour, then gives up and tells you. If it was restarted since, Rowsafe skips it and says so.

Disk forecast

From 14 days of disk use, Rowsafe tells you when the disk will be full ("in about 9 days"), ignoring one-off spikes. It needs about 2 days of history. disk_full_forecast warns 14 days ahead.

Table and index insights

About every 30 minutes, from catalog statistics (never your rows):

  • largest tables and indexes, and their growth;
  • unused and duplicate indexes;
  • wasted space (bloat);
  • tables with many dead rows;
  • tables read by full scans (index recommendations test a fix);
  • transaction and multixact ID age.

Buttons: Remove, Rebuild index, Clean up. CLI: rowsafe insights app.

Slow queries

With pg_stat_statements on (Turn on query statistics, then a restart), Rowsafe keeps 14 days of per-query timing. It shows the queries that took the most time and which got slower: average time more than doubled, adding at least 5 ms per call or a minute in all.

Query plans (PostgreSQL 12+): for the busiest queries, a plan in plain words, like "Reads the whole table orders: about 2.1 million rows." The agent asks PostgreSQL how it would run the query, without running it and without values (conditions show $1). They're estimates, not timings from real runs: Rowsafe never turns on auto_explain.

rowsafe top app                   # last 24 hours
rowsafe top app --since 168h --sort calls   # last 7 days, by number of calls

Uptime

Each minute the agent reports whether it could query the database. You see uptime over 24 hours, 7 and 30 days, and each outage. Minutes with the agent offline don't count; agent_offline covers them.

Your weekly Pulse

Every Monday morning, per database: health score, backups and Proof, growth, storage cost, the second copy, disk forecast, top fixes, top recommendation, slowest queries and open alerts.

On for new organizations. It goes to the addresses you choose, or your email alert channels. Change it under Settings → Weekly Pulse email; every email has a one-click unsubscribe.

Alert rules

Rules are checked every 30 seconds. An alert fires once its condition has held for For.

RuleSeverityDefault thresholdForFires when
backup_stalecritical26 hours15mNo successful backup in the threshold, or an active database was never backed up after 12 hours.
full_backup_stalewarning8 days15mNo successful full backup in the threshold.
drill_failedwarningThe latest Proof failed.
drill_overduewarning8 days15mNo Proof passed in the threshold.
wal_archiving_failingcritical10mArchiving keeps failing. Point-in-time recovery stops at the last archived segment, and pg_wal grows.
postgres_unreachablecritical5mThe agent is up but can't query PostgreSQL.
agent_offlinecritical5 minutes1mNo heartbeat from the agent.
restore_point_unconfirmedwarning15mA Mark was written but archiving hasn't moved past it.
awaiting_restartwarning24 hoursA plan was applied, but PostgreSQL wasn't restarted.
disk_free_lowwarning15%5mFree disk on the data directory's filesystem below the threshold.
disk_free_criticalcritical5%5mSame, lower threshold.
disk_full_forecastwarning (critical under 3 days)14 days30mAt the last two weeks' growth rate, the disk fills within the threshold.
connections_highwarning80%5mConnections above the share of max_connections.
connections_criticalcritical95%2mSame, higher threshold.
long_transactionwarning30 minutesA transaction open longer than the threshold.
idle_in_transactionwarning10 minutesA session idle in an open transaction longer than the threshold.
xid_wraparoundcritical50%Transaction ID headroom below the threshold.
multixact_wraparoundcritical50%Multixact ID headroom (row locks shared by several transactions) below the threshold.
replication_slot_inactivewarning1 GiB15mAn inactive replication slot holds back more WAL than the threshold.
blocked_querieswarning60 seconds1mA query waited longer than the threshold for another session's lock.
replication_lagwarning5 minutes5mA replica is further behind than the threshold.
deadlockswarning5More deadlocks than the threshold in 10 minutes.
cache_hit_lowinfo90%30mCache hit ratio below the threshold with real read traffic.
pooler_downcritical2mPgBouncer doesn't answer (only where pooling is on or monitored).
pooler_clients_waitingwarning2 seconds5mClients waited longer than the threshold for a connection in PgBouncer.
second_copy_failingwarning30 minutes5mChanges haven't reached the second copy for longer than the threshold, or some were left out. PostgreSQL and the first storage aren't affected.
rls_driftwarningA security scan found a new row-level security gap: a table your API reaches without it, a table with no policies, a policy that lets every row through, or a public storage bucket. PostgreSQL only.
  • Critical: recoverability or availability is degrading now. Warning: within a working day. Info: for the record.
  • Backup, archiving, Proof and reachability rules wait until backups are on, so a new database doesn't page you.
  • Admins can change or turn off any rule under Alerts (rowsafe alerts rules).

How alerts behave

  • One open alert per rule and target. It resolves when the condition clears, and you're told.
  • A critical alert repeats every 4 hours until acknowledged.
  • No data is not good news. Without fresh metrics an alert keeps its state; a silent agent raises agent_offline.
  • Fix it on an alert applies the fix, or opens Health when there's a choice.
rowsafe alerts                # firing alerts (--all adds resolved ones, --resolved shows only those)
rowsafe alerts ack alr_...    # acknowledge: no more reminders

Notification channels

Add and test channels under Settings → Alerts and notifications. Each has a minimum severity (default warning). Messages say what, where, since when, the value and threshold, and link to Fix it when there is one.

TypeDestinationNotes
emailUp to 20 addresses (repeat --address)Plain text.
slackA Slack incoming webhook
discordA Discord webhookMentions are off, so nobody is pinged.
teamsA Microsoft Teams incoming webhook or Workflows URLA card with the details.
pagerdutyA service's Events API v2 integration key (routing key), US or EU accountOpens an incident and resolves it when the alert clears.
opsgenieAn API integration's key, US or EU accountPriority from severity (critical P1). Closes the alert when it clears.
telegramA bot token (from @BotFather) and a chat ID (or @channel)Add the bot to the chat first.
ntfyA server (default https://ntfy.sh), a topic and an optional access tokenPriority from severity. On a public server, pick a topic nobody can guess.
webhookAny public https URLJSON, signed. The signing secret is shown once. See Webhooks.

Tests send at once, whatever the severity. URLs, keys, tokens and topics are secrets and never shown in full again. Up to 20 channels per organization.

Edit on GitHub