Background
Sections
IntroductionFoundations1. Resource Hierarchy2. Resource Manager3. Identity and RBAC4. Regions and Availability5. Naming and TaggingVirtual Machines1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetVirtual Network1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetBlob Storage1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure SQL Database1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Kubernetes Service1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Container Registry1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetMicrosoft Entra ID1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure RBAC1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Functions1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAPI Management1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure App Configuration1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Machine Learning1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Monitor1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure AI Foundry1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and Cheatsheet

6. Integrations

8 min read

No database is an island, and a relational database is the most connected thing in most architectures. This page covers the services Azure SQL Database is almost always paired with, and — more usefully — the glue, because "how do these two talk to each other securely" is where the real work is.

The two glue mechanisms that recur everywhere

Learn these once and most Azure integration questions answer themselves.

1. Managed identity + a contained database user

The keyless way an Azure resource authenticates to the database. Note the shape carefully, because it is a two-sided operation and half of the failures come from doing only one side:

# Azure side: the app has an identity
resource "azurerm_user_assigned_identity" "api" {
  name                = "id-orders-api-prod"
  resource_group_name = azurerm_resource_group.app.name
  location            = azurerm_resource_group.app.location
}

resource "azurerm_linux_web_app" "api" {
  # ...
  identity {
    type         = "UserAssigned"
    identity_ids = [azurerm_user_assigned_identity.api.id]
  }
  app_settings = {
    # No password. The driver acquires a token for this identity.
    "ConnectionStrings__Orders" = "Server=tcp:${var.sql_fqdn},1433;Database=sqldb-orders-prod;Authentication=Active Directory Managed Identity;User Id=${azurerm_user_assigned_identity.api.client_id};Encrypt=True;"
  }
}
-- Database side: the identity is a user with the narrowest useful role.
-- Run as the Entra admin, once per database, per identity.
CREATE USER [id-orders-api-prod] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [id-orders-api-prod];
ALTER ROLE db_datawriter ADD MEMBER [id-orders-api-prod];
-- Better still, for anything mature:
-- GRANT EXECUTE ON SCHEMA::app TO [id-orders-api-prod];  -- procedures only, no table access

Why this is not an Azure RBAC role assignment. There is no Azure SQL Data Reader built-in role, and there never will be one that works this way — data-plane authorisation for SQL lives in SQL, because the granularity (table, column, row, procedure) is far finer than ARM's model. This is the control plane vs. data plane split made concrete, and it is the single most common integration misunderstanding.

A prerequisite people miss: for the server to resolve group memberships and some principal types when creating external users, its identity may need the Entra Directory Readers role. If CREATE USER ... FROM EXTERNAL PROVIDER fails with a "Principal ... not found" error and the principal plainly exists, this is usually why.

2. Private endpoint + Private DNS zone

The way a caller reaches the database without traversing the public internet.

  • The private endpoint targets the sqlServer sub-resource (this is the string you pass; getting it wrong is a common Terraform error).
  • The Private DNS zone is privatelink.database.windows.net, linked to every VNet that must resolve it.
  • The magic is in the CNAME chain: myserver.database.windows.netmyserver.privatelink.database.windows.net → the private IP. The connection string does not change — which is exactly why this works for applications that can't be modified.
  • Pair it with public_network_access_enabled = false, or you have added a private path without removing the public one.

The failure signature to recognise: the app resolves the public IP and times out. Nine times in ten the VNet isn't linked to the Private DNS zone, or the caller is resolving through a custom DNS server that doesn't forward to Azure DNS (168.63.129.16). Check nslookup output before checking anything else.

The integration map

Pairs with Why The glue
Microsoft Entra ID Who can administer it, who can read it, without passwords Entra admin group on the logical server + contained users FROM EXTERNAL PROVIDER; azureADOnlyAuthentication = true to close the password path
Azure Key Vault The customer-managed key for TDE; any legacy connection strings you haven't eliminated yet Server system-assigned identity granted Key Vault Crypto Service Encryption User on the vault; for app settings, a Key Vault reference resolved via the app's managed identity
Azure Private Link Reach the database without a public endpoint Private endpoint on the sqlServer sub-resource + privatelink.database.windows.net zone
App Service / Functions / Container Apps The thing that actually queries it Managed identity + contained user (above) + VNet integration on the caller so it can reach the private endpoint
Azure Kubernetes Service Same, for containerised callers Workload identity federating a Kubernetes service account to an Entra app/identity, then the same contained user. Do not mount a connection string as a Secret
Azure Monitor / Log Analytics See what it's doing A diagnostic setting (off by default) routing SQLInsights, Errors, Timeouts, Blocks, Deadlocks, QueryStoreRuntimeStatistics and Basic metrics to a workspace; then KQL and alert rules
Azure Data Factory / Synapse pipelines Load into it, extract out of it A linked service authenticated by the data factory's managed identity, plus a managed private endpoint in the managed VNet so the runtime reaches a private database. A self-hosted integration runtime is the on-premises answer
Azure Databricks / Fabric Analytics over operational data JDBC via the Spark connector with Entra token auth; realistically, though, read from a replica or a copy — don't run analytical scans against the OLTP primary
Azure Logic Apps / Power Apps / Power BI Low-code consumers The SQL connector, authenticated by managed identity where supported; Power BI via DirectQuery (hits the primary — point it at a read replica) or Import (doesn't)
Azure Cache for Redis Take read pressure off the database Application-side cache-aside. The database integration is "there isn't one" — and that's the point; the app owns invalidation
Azure API Management Never expose the database; expose an API APIM in front of the service that owns the data. Listed here because "can APIM query SQL directly?" is asked often enough to answer: it can, and you shouldn't
Azure Backup / long-term retention Compliance retention beyond the PITR window LTR policy on the database itself — not Azure Backup, which does not manage Azure SQL Database. Knowing which service owns backup here is a common gap
Azure Elastic Jobs The SQL Agent replacement An Elastic Job agent (itself backed by a small database) running T-SQL on a schedule across one or many target databases. This is the answer to "where did SQL Agent go"

[Image Prompt: 2D minimalistic hub-and-spoke diagram with an Azure SQL Database at the centre connected by labelled edges to Microsoft Entra ID, Azure Key Vault, Private Link, App Service, Azure Functions, Azure Kubernetes Service, Azure Data Factory, Azure Monitor, Azure Cache for Redis, and Power BI, flat design, clean vector art style, white background]

Three integration patterns worth knowing by name

Read replica routing

Business Critical gives you a readable secondary at no extra cost, and Hyperscale gives you named replicas. Routing to them is a connection-string change, not an architecture change:

Server=tcp:sql-orders-prod.database.windows.net,1433;Database=sqldb-orders-prod;
Authentication=Active Directory Managed Identity;ApplicationIntent=ReadOnly;Encrypt=True;

Point reporting queries, exports, and Power BI DirectQuery at that connection string. Teams pay for Business Critical and then send every query to the primary, which is buying a second server and leaving it switched off.

The catch: the secondary is asynchronously applied for read purposes, so a read-your-own-write immediately after a commit may not see it. Fine for a dashboard, wrong for a checkout confirmation.

Change feed out of the database

When something downstream needs to react to a row changing, the options in ascending order of robustness:

  • Change Tracking — lightweight, tells you which rows changed since a version. Enough for a sync job. Built in.
  • Change Data Capture (CDC) — the full before/after, read from change tables. Heavier, and worth checking tier support ⚠️ verify current CDC availability by tier against current Azure docs.
  • Outbox pattern — the application writes a domain event to an outbox table in the same transaction as the business change, and a separate process publishes it to Service Bus or Event Grid. More code, but it is the only option that gives you transactional consistency between "the row changed" and "the event was emitted". For anything that matters, this is the answer.

Note what isn't on the list: there is no native "Azure SQL → Event Grid" trigger comparable to Blob Storage's. Don't design as though there is.

Failover group as the application's endpoint

If you deploy a failover group, applications should connect to the listener name (<fog-name>.database.windows.net), not the server name. The listener follows the primary, so a regional failover requires zero configuration change on the caller. Connecting to the server name directly is the mistake that turns a two-minute failover into a two-hour redeployment.

Read-only workloads can use the group's read-only listener, which follows the secondary.

What you should be able to do now

Wire an application to this database with no password anywhere, over a private network path, with telemetry flowing — and explain why granting the app Contributor in Azure RBAC would not have helped it read a single row.


Next: Production →

← Back to the Azure SQL Database overview · ← Previous: Deployment