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

4. Getting Started

6 min read

One database, one table, one row — three ways. This page is deliberately throwaway: hard-coded names, a public endpoint, an IP firewall rule, no variables, no state backend, no pipeline. Anything production-shaped lives in Deployment, and copying from this page into a pull request is how you get a review comment.

Everything goes into one resource group so that teardown is a single command.

The task

Create a logical server and one small database, connect, create a table, insert a row, read it back, and delete everything.

Path 1 — Azure Portal

  • Search for SQL databases and choose Create.
  • On Basics, pick your subscription and a new resource group, name the database db-demo, and create a new logical server — the server name must be globally unique. Choose Microsoft Entra-only authentication and set yourself as the Entra admin.
  • Still on Basics, open Configure database and pick General Purpose → Serverless, drop the max vCores to the minimum, and set backup redundancy to Locally-redundant — this is a demo, not a system of record.
  • On Networking, set connectivity to Public endpoint and toggle Add current client IP address to yes.
  • Create, then open the database's Query editor (preview) blade and sign in with Entra to run SQL in the browser without installing anything.

Portal navigation changes often; the blade names above are stable, the exact button labels are not.

Path 2 — Azure CLI

Copy-pasteable. Change SQL_SERVER to something globally unique before running.

# --- variables -------------------------------------------------------------
RG=rg-sqldemo
LOC=uksouth
SQL_SERVER=sql-demo-$RANDOM$RANDOM       # must be globally unique
DB=db-demo
MY_IP=$(curl -s https://api.ipify.org)
ME_UPN=$(az ad signed-in-user show --query userPrincipalName -o tsv)
ME_OID=$(az ad signed-in-user show --query id -o tsv)

# --- throwaway resource group ---------------------------------------------
az group create -n $RG -l $LOC

# --- logical server, Entra-only auth (no SQL password anywhere) ------------
az sql server create \
  --name $SQL_SERVER \
  --resource-group $RG \
  --location $LOC \
  --enable-ad-only-auth \
  --external-admin-principal-type User \
  --external-admin-name "$ME_UPN" \
  --external-admin-sid "$ME_OID"

# --- firewall: just my machine --------------------------------------------
az sql server firewall-rule create \
  --resource-group $RG --server $SQL_SERVER \
  --name allow-my-ip --start-ip-address $MY_IP --end-ip-address $MY_IP

# --- the smallest sensible database: General Purpose serverless ------------
az sql db create \
  --resource-group $RG --server $SQL_SERVER --name $DB \
  --edition GeneralPurpose \
  --compute-model Serverless \
  --family Gen5 --capacity 1 \
  --min-capacity 0.5 \
  --auto-pause-delay 60 \
  --backup-storage-redundancy Local

az sql db show -g $RG -s $SQL_SERVER -n $DB -o table

Now connect and do something. sqlcmd with -G uses Entra authentication, so there is still no password in play:

sqlcmd -S ${SQL_SERVER}.database.windows.net -d $DB -G -Q "
CREATE TABLE dbo.widget (id INT IDENTITY PRIMARY KEY, name NVARCHAR(50) NOT NULL);
INSERT INTO dbo.widget (name) VALUES ('hello');
SELECT id, name FROM dbo.widget;
"

If that first command hangs for 30–60 seconds, the database has auto-paused and is resuming. That is the serverless behaviour from Core Concepts, observed live.

Two more commands worth running once, because they make the abstractions concrete:

# Scale it — watch this take minutes and drop connections at the end
az sql db update -g $RG -s $SQL_SERVER -n $DB --capacity 2

# What has it actually been using?
sqlcmd -S ${SQL_SERVER}.database.windows.net -d $DB -G -Q \
  "SELECT TOP 10 end_time, avg_cpu_percent, avg_data_io_percent FROM sys.dm_db_resource_stats ORDER BY end_time DESC;"

PowerShell Az equivalent

Included here because SQL Server shops are overwhelmingly PowerShell-first — this is one of the few services where the Az module is genuinely the house language rather than an afterthought.

New-AzResourceGroup -Name rg-sqldemo -Location uksouth

New-AzSqlServer -ResourceGroupName rg-sqldemo -ServerName 'sql-demo-uniquename' `
  -Location uksouth -EnableActiveDirectoryOnlyAuthentication `
  -ExternalAdminName (Get-AzADUser -SignedIn).UserPrincipalName

New-AzSqlDatabase -ResourceGroupName rg-sqldemo -ServerName 'sql-demo-uniquename' `
  -DatabaseName 'db-demo' -Edition GeneralPurpose -ComputeModel Serverless `
  -ComputeGeneration Gen5 -VCore 1 -MinimumCapacity 0.5

Path 3 — Terraform (minimal)

The smallest thing that stands the same resources up. The parameterised, reviewable version — modules, variables, remote state — is in Deployment.

terraform {
  required_providers {
    azurerm = { source = "hashicorp/azurerm", version = "~> 4.0" }
  }
}

provider "azurerm" {
  features {}
}

data "azurerm_client_config" "current" {}

resource "azurerm_resource_group" "demo" {
  name     = "rg-sqldemo"
  location = "uksouth"
}

resource "azurerm_mssql_server" "demo" {
  name                          = "sql-demo-uniquename" # globally unique
  resource_group_name           = azurerm_resource_group.demo.name
  location                      = azurerm_resource_group.demo.location
  version                       = "12.0" # the only value; it means "Azure SQL", not SQL Server 2014
  minimum_tls_version           = "1.2"
  public_network_access_enabled = true # demo only

  azuread_administrator {
    login_username              = "sqladmins"
    object_id                   = data.azurerm_client_config.current.object_id
    tenant_id                   = data.azurerm_client_config.current.tenant_id
    azuread_authentication_only = true # no SQL login, no password
  }
}

resource "azurerm_mssql_firewall_rule" "my_ip" {
  name             = "allow-my-ip"
  server_id        = azurerm_mssql_server.demo.id
  start_ip_address = "203.0.113.10" # your IP
  end_ip_address   = "203.0.113.10"
}

resource "azurerm_mssql_database" "demo" {
  name                        = "db-demo"
  server_id                   = azurerm_mssql_server.demo.id
  sku_name                    = "GP_S_Gen5_1" # General Purpose, Serverless, Gen5, 1 vCore
  min_capacity                = 0.5
  auto_pause_delay_in_minutes = 60
  storage_account_type        = "Local" # cheap backup redundancy for a demo
}

output "fqdn" { value = azurerm_mssql_server.demo.fully_qualified_domain_name }
terraform init && terraform apply

Read sku_name carefullyGP_S_Gen5_1 encodes four of the five axes from Core Concepts in eleven characters: tier (GP), compute model (S for serverless), hardware family (Gen5), and vCore count (1). BC_Gen5_4 is Business Critical provisioned with four vCores. HS_Gen5_2 is Hyperscale. Once you can read that string, most Azure SQL Terraform is readable.

Note also that azurerm_mssql_server.version = "12.0" is not a SQL Server version — it is a legacy constant meaning "Azure SQL Database", and it is the only accepted value. It confuses everyone once.

[Image Prompt: 2D minimalistic diagram comparing three provisioning paths — Azure Portal, Azure CLI, and Terraform — converging on the same logical SQL server containing one database, with a firewall rule and a Microsoft Entra admin attached to the server, flat design, clean vector art style, white background]

Teardown

Do this now, not later. Deleting the resource group takes the server, the database, the firewall rules, and the backups with it — and it is the cleanest teardown Azure gives you, which is a genuine advantage over per-resource cleanup in AWS.

az group delete -n rg-sqldemo --yes --no-wait

Terraform users: terraform destroy.

One caveat worth knowing now rather than at invoice time: if you had enabled long-term retention backups, deleting the database does not automatically delete those LTR backups, and they keep billing. This demo used the default retention only, so there is nothing left behind — but the general rule is in Deployment.

What you should be able to do now

Stand up a working Azure SQL database in under five minutes, read a sku_name string correctly, and watch a serverless database pause and resume — which makes every later discussion of cost concrete rather than theoretical.


Next: Deployment →

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