Set up Azure SQL Database
Set up Database Observability with Grafana Cloud to collect telemetry from Azure SQL Database using Grafana Alloy. You configure your Azure SQL database and Alloy to forward telemetry to Grafana Cloud.
If you already use the SQL Server integration, Database Observability extends it with query-level telemetry collected by the database_observability.sql_server Alloy component.
What you’ll achieve
In this article, you:
- Confirm Query Store is enabled on the database you want to monitor.
- Create a contained monitoring user with the required privileges.
- Configure Alloy with the Database Observability components.
- Forward telemetry to Grafana Cloud.
- Verify that telemetry appears in Database Observability.
Setup steps
Setting up Database Observability for Azure SQL Database has three steps:
- Set up your database: Prepare your Azure SQL database so Alloy can collect from it.
- Configure Grafana Alloy: Configure how Alloy collects telemetry and sends it to Grafana Cloud.
- Verify telemetry in Grafana Cloud: Check telemetry status and confirm that query metrics appear in Database Observability.
Before you begin
To complete this setup, you need:
- An Azure SQL Database with Query Store available.
- A server administrator, or a user that can create users and grant privileges in the database you want to monitor.
- The fully qualified server name, for example
<SERVER_NAME>.database.windows.net, and the name of the database you want to monitor. - A planned Grafana Alloy deployment location with network access to your Azure SQL Database endpoint on port
1433.
Estimated setup time: 15-30 minutes.
Note
Alloy should connect directly to the database host. Avoid connecting Alloy to the database through a load balancer or connection pooler as it would limit Alloy’s ability to collect accurate telemetry.
Set up your database
Important
On Azure SQL Database, the
USEstatement can’t switch between databases. Point each connection’sdata_source_nameat one specific user database, never atmaster. Schema details, query metrics, and query text then all cover that single database. To monitor several databases on the same logical server, add onedatabase_instanceblock per database in a singledatabase_observability.sql_servercomponent, each with its owndata_source_name.
In this step, you’ll prepare your Azure SQL database for monitoring by confirming Query Store is enabled, creating a monitoring user, and granting the permissions Database Observability needs.
Complete this before configuring Alloy. Without it, Alloy can connect to your database, but it won’t be able to collect the telemetry required for Database Observability.
Enable Query Store
Query Store is the per-database feature Database Observability reads for query metrics and query text. On Azure SQL Database, Query Store is on by default, so you usually only need to confirm it’s writable.
Connect to the database you want to monitor and check the Query Store state:
SELECT actual_state_desc FROM sys.database_query_store_options;The actual_state_desc column should return READ_WRITE. If it returns READ_ONLY or OFF, re-enable Query Store on the connected database:
ALTER DATABASE CURRENT SET QUERY_STORE = ON (OPERATION_MODE = READ_WRITE);On Azure SQL Database you can’t name another database in ALTER DATABASE. Use ALTER DATABASE CURRENT while connected to the database you want to change.
Create a monitoring user and grant privileges
Connect to the database you want to monitor, not master, as an administrator and create a contained monitoring user named db-o11y:
CREATE USER [db-o11y] WITH PASSWORD = '<DB_O11Y_PASSWORD>';
GRANT CONNECT TO [db-o11y];
GRANT VIEW DEFINITION TO [db-o11y]; -- schema metadata
GRANT VIEW DATABASE STATE TO [db-o11y]; -- Query Store, database resource metrics, and session activityReplace <DB_O11Y_PASSWORD> with a strong password.
Repeat this in every database you want to monitor. Because USE can’t switch databases on Azure SQL Database, each database needs its own contained user and its own data_source_name.
Verify user privileges
Connect with the db-o11y credentials, not the administrator, against the database you want to monitor, then confirm the effective privileges:
-- Query Store is readable on the connected database. Expect one row with actual_state_desc = READ_WRITE.
SELECT DB_NAME() AS database_name, actual_state_desc FROM sys.database_query_store_options;
-- Effective permissions on the connected database. Expect 1 for both columns.
SELECT
HAS_PERMS_BY_NAME(DB_NAME(), 'DATABASE', 'VIEW DEFINITION') AS can_view_definition,
HAS_PERMS_BY_NAME(DB_NAME(), 'DATABASE', 'VIEW DATABASE STATE') AS can_view_database_state;If the first query returns no rows or an error, or either permission check returns 0, re-run the grants in Create a monitoring user and grant privileges while connected to that user database.
Database setup checkpoint
Continue to Alloy configuration only after these conditions are true:
- Query Store is
READ_WRITEon the database you point Alloy at (SELECT actual_state_desc FROM sys.database_query_store_options;returnsREAD_WRITE). - The
db-o11ycontained user exists in that database and hasVIEW DATABASE STATEandVIEW DEFINITION. - The Verify user privileges queries confirm the grants are effective as
db-o11y. - The
db-o11yuser can connect from the network where Alloy will run, on port1433.
After these checks pass, your Azure SQL database is ready for Database Observability. Next, configure Alloy so it can collect telemetry from the database endpoint and send it to Grafana Cloud.
Configure Grafana Alloy
After you set up your database, configure Alloy to collect telemetry and send it to Grafana Cloud. These instructions use a custom Alloy configuration file, which you manage outside the Database Observability setup flow in Grafana Cloud.
Make sure you’re on a supported Alloy version
Alloy 1.22.0 or later is required for Database Observability for SQL Server. Find the latest stable version on Docker Hub. To update, refer to the Alloy release notes.
Note
New to Alloy?
Grafana Alloy is an open source collector that sends your data to Grafana Cloud. Database Observability needs it to collect metrics and query telemetry from your database.
If you don’t have it installed, refer to Install Grafana Alloy before you continue.
Add the Azure SQL Database configuration blocks
Add these blocks to Alloy for Azure SQL Database. Replace <DB_NAME>. Create a local.file with the data source name string, for example, "sqlserver://<DB_O11Y_USER>:<DB_O11Y_PASSWORD>@<SERVER_FQDN>:<DB_PORT>?database=<DB_DATABASE>&encrypt=true":
local.file "sqlserver_secret_<DB_NAME>" {
filename = "/var/lib/alloy/sqlserver_secret_<DB_NAME>"
is_secret = true
}
database_observability.sql_server "sqlserver_<DB_NAME>" {
data_source_name = local.file.sqlserver_secret_<DB_NAME>.content
forward_to = [loki.relabel.database_observability_sqlserver_<DB_NAME>.receiver]
cloud_provider {
azure {
subscription_id = "<AZURE_SUBSCRIPTION_ID>"
resource_group = "<AZURE_RESOURCE_GROUP>"
server_name = "<AZURE_SERVER_NAME>"
}
}
}
loki.relabel "database_observability_sqlserver_<DB_NAME>" {
forward_to = [loki.write.grafana_cloud_loki.receiver]
rule {
target_label = "instance"
replacement = "<INSTANCE_LABEL>"
}
}
discovery.relabel "database_observability_sqlserver_<DB_NAME>" {
targets = database_observability.sql_server.sqlserver_<DB_NAME>.targets
rule {
target_label = "job"
replacement = "integrations/db-o11y"
}
// OPTIONAL: relabel `instance` to `dsn` before overwriting `instance`;
// the `dsn` label is used in the integration with the knowledge graph
rule {
source_labels = ["instance"]
target_label = "dsn"
}
rule {
target_label = "instance"
replacement = "<INSTANCE_LABEL>"
}
}
prometheus.scrape "database_observability_sqlserver_<DB_NAME>" {
targets = discovery.relabel.database_observability_sqlserver_<DB_NAME>.output
forward_to = [prometheus.remote_write.metrics_service.receiver]
}Replace the placeholders:
DB_NAME: Database name Alloy uses in component identifiers (appears in component names and secret filenames).AZURE_SUBSCRIPTION_ID: Azure Subscription ID for your Azure SQL database.AZURE_RESOURCE_GROUP: Azure Resource Group that holds the logical server.AZURE_SERVER_NAME: Azure logical server name, for exampleorders-dbfor the hostorders-db.database.windows.net.INSTANCE_LABEL: Value that sets theinstancelabel on logs and metrics (optional).- Secret file content example:
"sqlserver://<DB_O11Y_USER>:<DB_O11Y_PASSWORD>@<SERVER_FQDN>:<DB_PORT>?database=<DB_DATABASE>&encrypt=true".DB_O11Y_USER: Contained user Alloy uses to connect (for example,db-o11y).DB_O11Y_PASSWORD: Password for the database user.SERVER_FQDN: Azure logical server fully qualified domain name (for example,<SERVER_NAME>.database.windows.net).DB_PORT: Database port number (default:1433).DB_DATABASE: The user database to monitor. It must have Query Store enabled and must not bemaster.
Because Azure SQL Database collects from only the single database in the DSN, give each database its own contained user and database= value. Repeat the blocks above for each database, or add one database_instance block per database in a single database_observability.sql_server component.
Find more about the options supported by the database_observability.sql_server component in the reference documentation.
The cloud_provider block integrates Database Observability with Cloud Provider Observability.
To navigate between query performance and Azure infrastructure metrics, refer to Preconfigured dashboards and alerts for Azure metrics.
Add Prometheus and Loki write configuration
Add the Prometheus remote write and Loki write configuration. From Grafana Cloud, open your stack to get the URLs and generate API tokens:
prometheus.remote_write "metrics_service" {
endpoint {
url = sys.env("GCLOUD_HOSTED_METRICS_URL")
basic_auth {
password = sys.env("GCLOUD_RW_API_KEY")
username = sys.env("GCLOUD_HOSTED_METRICS_ID")
}
}
}
loki.write "grafana_cloud_loki" {
endpoint {
url = sys.env("GCLOUD_HOSTED_LOGS_URL")
basic_auth {
password = sys.env("GCLOUD_RW_API_KEY")
username = sys.env("GCLOUD_HOSTED_LOGS_ID")
}
}
}Replace the placeholders:
GCLOUD_HOSTED_METRICS_URL: Your Grafana Cloud Prometheus remote write URL.GCLOUD_HOSTED_METRICS_ID: Your Grafana Cloud Prometheus instance ID (username).GCLOUD_HOSTED_LOGS_URL: Your Grafana Cloud Loki write URL.GCLOUD_HOSTED_LOGS_ID: Your Grafana Cloud Loki instance ID (username).GCLOUD_RW_API_KEY: Grafana Cloud API token with write permissions.
Verify telemetry in Grafana Cloud
After Alloy starts, verify that Database Observability is receiving telemetry.
- In Grafana Cloud, open Database Observability.
- Go to Configuration.
- Select Telemetry status.
- Select your database instance.
- Confirm that telemetry status checks pass.
- Open Queries overview and confirm that query metrics appear.
After telemetry appears, the database instance should be visible and Queries overview should show query metrics. Additional data such as query samples, wait events, schema details, and explain plans becomes available as Alloy collects it and as the database engine supports it.
Telemetry can take a few minutes to appear. For detailed status checks, refer to Verify telemetry status.
Troubleshoot first-run issues
If data doesn’t appear after setup:
- If the database instance doesn’t appear in Database Observability, check Alloy connectivity and labels.
- If telemetry status checks fail, use the Configuration page to identify the failed requirement.
- If schema details appear but query metrics don’t, confirm that Query Store is
READ_WRITEon the database in the connection string and that thedb-o11yuser hasVIEW DATABASE STATEthere. - If nothing is collected, confirm the DSN points at a user database and not
master. Azure SQL Database can’t switch databases withUSE, so amasterconnection collects nothing. - If Alloy can’t connect to the database, check firewall rules, virtual network settings, DNS, and that encryption is enabled in the DSN.
For detailed guidance, refer to Troubleshoot Alloy or Troubleshoot SQL Server.


