Monitor multiple databases
As your infrastructure grows beyond a single database, you need to monitor multiple database instances. This guide covers deployment patterns, configuration strategies, and labeling best practices for managing multiple databases with Database Observability.
Before you begin
Complete setup for at least one database:
You also need:
- Grafana Alloy running and connected to Grafana Cloud
- Grafana Cloud remote write credentials for Prometheus and Loki
Choose a deployment pattern
Choose a deployment pattern based on your infrastructure and scale requirements.
Single Alloy instance
One Alloy instance monitors all databases.
┌─────────────────┐
│ Grafana Alloy │
│ ┌─────────┐ │ ┌──────────┐
│ │ MySQL 1 │──┼────▶│ mysql-1 │
│ ├─────────┤ │ └──────────┘
│ │ MySQL 2 │──┼────▶│ mysql-2 │
│ ├─────────┤ │ └──────────┘
│ │ PG 1 │──┼────▶│ postgres │
│ └─────────┘ │ └──────────┘
└────────┬────────┘
│
▼
Grafana CloudAdvantages:
- Simple to deploy and manage
- Single configuration file
- Lower resource overhead
Disadvantages:
- Single point of failure
- Network latency to remote databases
- Scaling limits
Best for:
- Small to medium deployments (< 20 databases)
- Databases in same network/region
- Development and staging environments
Distributed Alloy instances
Deploy Alloy alongside each database or group of databases.
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Region A │ │ Region B │ │ Region C │
│ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │
│ │ Alloy │ │ │ │ Alloy │ │ │ │ Alloy │ │
│ │ ↓ │ │ │ │ ↓ │ │ │ │ ↓ │ │
│ │ MySQL │ │ │ │ PG │ │ │ │ MySQL │ │
│ └────────┘ │ │ └────────┘ │ │ └────────┘ │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │
└─────────────────┼─────────────────┘
▼
Grafana CloudAdvantages:
- High availability (one Alloy failure doesn’t affect others)
- Low latency to local databases
- Scales horizontally
- Aligns with infrastructure boundaries
Disadvantages:
- More instances to manage
- Distributed configuration
- Higher total resource usage
Best for:
- Large deployments (20+ databases)
- Multi-region infrastructure
- Production environments requiring high availability
Configure multiple databases
Single Alloy with multiple databases
Add a component block for each database:
// ====================
// Database 1: MySQL orders
// ====================
local.file "mysql_orders_secret" {
filename = "/var/lib/alloy/mysql_orders_dsn"
is_secret = true
}
prometheus.exporter.mysql "orders" {
data_source_name = local.file.mysql_orders_secret.content
enable_collectors = ["perf_schema.eventsstatements"]
}
database_observability.mysql "orders" {
data_source_name = local.file.mysql_orders_secret.content
forward_to = [loki.relabel.orders.receiver]
targets = prometheus.exporter.mysql.orders.targets
}
loki.relabel "orders" {
forward_to = [loki.write.default.receiver]
rule {
target_label = "instance"
replacement = "orders.db.example.com:3306"
}
rule {
target_label = "job"
replacement = "integrations/db-o11y"
}
rule {
target_label = "app"
replacement = "order-service"
}
}
discovery.relabel "orders" {
targets = database_observability.mysql.orders.targets
rule {
target_label = "job"
replacement = "integrations/db-o11y"
}
rule {
target_label = "instance"
replacement = "orders.db.example.com:3306"
}
rule {
target_label = "app"
replacement = "order-service"
}
}
prometheus.scrape "orders" {
targets = discovery.relabel.orders.output
forward_to = [prometheus.remote_write.default.receiver]
}
// ====================
// Database 2: PostgreSQL users
// ====================
local.file "pg_users_secret" {
filename = "/var/lib/alloy/pg_users_dsn"
is_secret = true
}
prometheus.exporter.postgres "users" {
data_source_names = [local.file.pg_users_secret.content]
enabled_collectors = ["stat_statements"]
autodiscovery {
enabled = true
}
}
database_observability.postgres "users" {
data_source_name = local.file.pg_users_secret.content
forward_to = [loki.relabel.users.receiver]
targets = prometheus.exporter.postgres.users.targets
}
loki.relabel "users" {
forward_to = [loki.write.default.receiver]
rule {
target_label = "instance"
replacement = "users.db.example.com:5432"
}
rule {
target_label = "job"
replacement = "integrations/db-o11y"
}
rule {
target_label = "app"
replacement = "user-service"
}
}
discovery.relabel "users" {
targets = database_observability.postgres.users.targets
rule {
target_label = "job"
replacement = "integrations/db-o11y"
}
rule {
target_label = "instance"
replacement = "users.db.example.com:5432"
}
rule {
target_label = "app"
replacement = "user-service"
}
}
prometheus.scrape "users" {
targets = discovery.relabel.users.output
forward_to = [prometheus.remote_write.default.receiver]
}
// ====================
// Shared outputs
// ====================
prometheus.remote_write "default" {
endpoint {
url = "https://prometheus-prod-01-us-east-0.grafana.net/api/prom/push"
basic_auth {
username = sys.env("GRAFANA_CLOUD_PROMETHEUS_USERNAME")
password = sys.env("GRAFANA_CLOUD_API_KEY")
}
}
}
loki.write "default" {
endpoint {
url = "https://logs-prod-us-east-0.grafana.net/loki/api/v1/push"
basic_auth {
username = sys.env("GRAFANA_CLOUD_LOKI_USERNAME")
password = sys.env("GRAFANA_CLOUD_API_KEY")
}
}
}Mixed database types
You can monitor both MySQL and PostgreSQL from the same Alloy instance:
// MySQL databases
database_observability.mysql "mysql_1" { /* ... */ }
database_observability.mysql "mysql_2" { /* ... */ }
// PostgreSQL databases
database_observability.postgres "pg_1" { /* ... */ }
database_observability.postgres "pg_2" { /* ... */ }Each component is independent and can have different configurations.
Choose a labeling strategy
Consistent labels help you filter and organize databases in Database Observability dashboards.
Required labels
These labels must be set correctly for Database Observability to function:
Recommended labels
Add these labels to organize and filter databases:
Label consistency
Labels must match between loki.relabel and discovery.relabel:
// Logs labels
loki.relabel "mydb" {
rule {
target_label = "instance"
replacement = "mydb.example.com:3306"
}
rule {
target_label = "environment"
replacement = "production"
}
}
// Metrics labels - must match!
discovery.relabel "mydb" {
rule {
target_label = "instance"
replacement = "mydb.example.com:3306" // Same value
}
rule {
target_label = "environment"
replacement = "production" // Same value
}
}For complete label guidance including best practices, environment variables, and troubleshooting, refer to the Labels reference.
Add cloud provider integrations
Add a cloud_provider block to correlate your database telemetry with infrastructure metrics from AWS CloudWatch or Azure Monitor. Cloud provider metadata is currently supported for AWS and Azure only.
AWS RDS / Aurora
database_observability.mysql "rds" {
data_source_name = local.file.rds_secret.content
forward_to = [loki.relabel.rds.receiver]
targets = prometheus.exporter.mysql.rds.targets
cloud_provider {
aws {
arn = "arn:aws:rds:us-east-1:123456789012:db:mydb"
}
}
}Azure Database
database_observability.postgres "azure" {
data_source_name = local.file.azure_secret.content
forward_to = [loki.relabel.azure.receiver]
targets = prometheus.exporter.postgres.azure.targets
cloud_provider {
azure {
subscription_id = "your-subscription-id"
resource_group = "your-resource-group"
server_name = "your-server-name"
}
}
}Troubleshoot multi-database setups
When databases don’t appear or data doesn’t correlate correctly, start with these multi-database-specific checks:
- Verify that every database has a unique
instancelabel. - Confirm the
instancevalue matches exactly between theloki.relabelanddiscovery.relabelblocks for the same database. - Check that
jobis exactlyintegrations/db-o11yon every component.
For detailed troubleshooting steps, refer to the dedicated guides:
Related documentation
- Tune Alloy collection: Optimize per-database settings
- Labels reference: Complete label documentation
- Verify telemetry status: Validate configuration health per database



