Most companies pay full price for Windows Server and SQL Server licenses on Azure VMs when they already own the licenses through Software Assurance. One line of Terraform changes that. Here's how to enforce it org-wide.
A company runs 50 Windows Server VMs on Azure. None have Azure Hybrid Benefit enabled. They're paying $0.312/hr per D4s_v5 instead of $0.192/hr. That's an extra $0.12/hr per VM they don't need to pay. Annual waste: $52,560. The fix? One line of Terraform. 🏷️
Here's the math for a single Standard_D4s_v5 (4 vCPU, 16 GB):
Without Hybrid Benefit (Windows license included): $0.312/hour
With Hybrid Benefit (bring your own license): $0.192/hour
Savings per VM: $0.12/hour (38%)
Per VM per year: $0.12 x 730 hours/month x 12 = $1,051
50 VMs per year: $52,560 saved 🤯
And you likely qualify if your company has Windows Server or SQL Server licenses with active Software Assurance or subscription licenses. Most enterprise EA agreements include this. Your licenses are sitting there, unused against your Azure workloads, costing you nothing to apply.
The fix is literally one property in your Terraform config. Let's apply it everywhere and make sure it never gets missed again. ⚡
🎯 What Is Azure Hybrid Benefit?
Azure Hybrid Benefit (AHB) lets you use your existing on-premises Windows Server and SQL Server licenses on Azure. Instead of paying the full VM price (which bundles an OS license), you pay only the compute cost, the same rate as a Linux VM.
It works for:
- Windows Server VMs (Standard and Datacenter editions with Software Assurance)
- SQL Server on VMs (Enterprise and Standard editions with Software Assurance)
- Azure SQL Database (vCore-based, provisioned tier)
- Azure SQL Managed Instance
- Red Hat and SUSE Linux (existing subscriptions)
You also get 180 days of dual-use rights: run the same license on-premises AND in Azure simultaneously during migration. No rush, no downtime pressure.
⚡ The One-Line Fix: Windows Server VMs
Before (paying for the license you already own):
resource "azurerm_windows_virtual_machine" "app_server" {
name = "vm-app-prod-01"
resource_group_name = azurerm_resource_group.prod.name
location = azurerm_resource_group.prod.location
size = "Standard_D4s_v5"
admin_username = "azureadmin"
admin_password = var.admin_password
# No license_type = paying full Windows price 💸
network_interface_ids = [azurerm_network_interface.app.id]
os_disk {
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2022-datacenter-azure-edition"
version = "latest"
}
}
After (using the license you already own):
resource "azurerm_windows_virtual_machine" "app_server" {
name = "vm-app-prod-01"
resource_group_name = azurerm_resource_group.prod.name
location = azurerm_resource_group.prod.location
size = "Standard_D4s_v5"
admin_username = "azureadmin"
admin_password = var.admin_password
license_type = "Windows_Server" # THIS LINE SAVES 38% 🎯
network_interface_ids = [azurerm_network_interface.app.id]
os_disk {
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2022-datacenter-azure-edition"
version = "latest"
}
}
That's it. license_type = "Windows_Server". Apply, and your hourly rate drops immediately. No reboot, no downtime, no migration. 🎯
🗃️ SQL Server: Even Bigger Savings
SQL Server licensing on Azure is where the real money is. The license cost for SQL Server Enterprise can be more expensive than the VM itself.
SQL Server on VMs
resource "azurerm_mssql_virtual_machine" "sql_prod" {
virtual_machine_id = azurerm_windows_virtual_machine.sql_server.id
sql_license_type = "AHUB" # Azure Hybrid Benefit
r_services_enabled = false
sql_connectivity_port = 1433
sql_connectivity_type = "PRIVATE"
auto_patching {
day_of_week = "Sunday"
maintenance_window_duration_in_minutes = 60
maintenance_window_starting_hour = 2
}
}
The sql_license_type values:
-
"PAYG"= Pay-as-you-go (full price, includes SQL license) -
"AHUB"= Azure Hybrid Benefit (bring your own SQL license) -
"DR"= Free for passive disaster recovery replicas
Azure SQL Database (vCore model)
resource "azurerm_mssql_database" "app_db" {
name = "sqldb-app-prod"
server_id = azurerm_mssql_server.prod.id
sku_name = "GP_Gen5_4"
license_type = "BasePrice" # AHB: pay only for compute, not SQL license
max_size_gb = 256
zone_redundant = true
tags = {
Environment = "prod"
CostCenter = "CC-1042"
ManagedBy = "terraform"
}
}
The license_type values for Azure SQL:
-
"LicenseIncluded"= Full price (includes SQL Server license) -
"BasePrice"= Azure Hybrid Benefit (bring your own license)
Azure SQL Elastic Pool
resource "azurerm_mssql_elasticpool" "shared_pool" {
name = "epool-shared-prod"
resource_group_name = azurerm_resource_group.prod.name
location = azurerm_resource_group.prod.location
server_name = azurerm_mssql_server.prod.name
license_type = "BasePrice" # AHB here too!
max_size_gb = 756
sku {
name = "GP_Gen5"
tier = "GeneralPurpose"
family = "Gen5"
capacity = 8
}
per_database_settings {
min_capacity = 0.25
max_capacity = 4
}
}
🏗️ Enforce It Org-Wide: The AHB-Aware Module
Don't rely on individual developers remembering to add license_type. Build a module that applies it automatically:
# modules/windows-vm/main.tf
variable "name" { type = string }
variable "resource_group_name" { type = string }
variable "location" { type = string }
variable "size" { type = string }
variable "subnet_id" { type = string }
variable "admin_username" { type = string }
variable "admin_password" { type = string sensitive = true }
variable "image_sku" { type = string default = "2022-datacenter-azure-edition" }
variable "tags" { type = map(string) default = {} }
variable "enable_hybrid_benefit" {
type = bool
default = true # ON by default - opt OUT if you don't have SA
description = "Enable Azure Hybrid Benefit. Requires Windows Server SA licenses."
}
resource "azurerm_network_interface" "this" {
name = "${var.name}-nic"
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "internal"
subnet_id = var.subnet_id
private_ip_address_allocation = "Dynamic"
}
tags = var.tags
}
resource "azurerm_windows_virtual_machine" "this" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
size = var.size
admin_username = var.admin_username
admin_password = var.admin_password
# AHB is ON by default - saves 38% on every Windows VM
license_type = var.enable_hybrid_benefit ? "Windows_Server" : "None"
network_interface_ids = [azurerm_network_interface.this.id]
os_disk {
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = var.image_sku
version = "latest"
}
tags = merge(var.tags, {
HybridBenefit = var.enable_hybrid_benefit ? "enabled" : "disabled"
ManagedBy = "terraform"
})
}
output "vm_id" { value = azurerm_windows_virtual_machine.this.id }
output "private_ip" {
value = azurerm_network_interface.this.private_ip_address
}
Usage:
module "app_server" {
source = "./modules/windows-vm"
name = "vm-app-prod-01"
resource_group_name = azurerm_resource_group.prod.name
location = azurerm_resource_group.prod.location
size = "Standard_D4s_v5"
subnet_id = azurerm_subnet.app.id
admin_username = "azureadmin"
admin_password = var.admin_password
# AHB is on by default - no action needed!
# Set enable_hybrid_benefit = false only if you DON'T have SA licenses
tags = {
Environment = "prod"
CostCenter = "CC-1042"
Owner = "team-backend"
Project = "api-platform"
}
}
Every Windows VM created through this module has AHB enabled by default. Teams that don't have Software Assurance can explicitly opt out. Everyone else saves 38% without thinking about it. ⚡
⚡ Quick Audit: Find VMs Without Hybrid Benefit
# Find all Windows VMs NOT using Azure Hybrid Benefit
az vm list --query "[?storageProfile.osDisk.osType=='Windows' && licenseType!='Windows_Server'].{
Name:name,
Size:hardwareProfile.vmSize,
RG:resourceGroup,
LicenseType:licenseType
}" --output table
# Find SQL databases not using AHB
az sql db list --server YOUR_SERVER --resource-group YOUR_RG \
--query "[?licenseType!='BasePrice' && !contains(sku.name, 'GP_S')].{
Name:name,
SKU:sku.name,
License:licenseType
}" --output table
Every Windows VM in that first list without Windows_Server as the license type is paying full price for a license you might already own. 🔥
💡 Architect Pro Tips
Verify your Software Assurance first. AHB requires active SA or subscription licenses. Check with your Microsoft account manager or procurement team before enabling. Enabling without valid licenses violates the agreement.
AHB stacks with Reserved Instances. Combine AHB (saves ~38% on licensing) with a 3-year Reserved Instance (saves ~50% on compute). Together they can reduce costs by up to 80% compared to pay-as-you-go. This is the single most impactful cost optimization for Windows workloads.
Windows Server Datacenter gives unlimited virtualization. If you have Datacenter edition licenses, you can apply AHB to unlimited VMs on Azure Dedicated Host. Standard edition is limited to 2 VMs per license.
SQL Server Enterprise: 1 core = 4 vCPUs. Each SQL Server Enterprise core license covers 4 vCPUs on Azure SQL Database General Purpose and Azure SQL Managed Instance. That's a 4:1 ratio, making enterprise licenses very efficient in the cloud.
Use "DR" license type for passive replicas. SQL Server disaster recovery replicas that aren't serving active traffic qualify for the free
"DR"license type. Don't pay for a license on a standby.Serverless Azure SQL does NOT support AHB. If your SKU starts with
GP_S(serverless), thelicense_typeparameter should not be set. Serverless pricing already excludes the license component.Adding AHB to existing VMs requires no downtime. You can apply
license_typeto running VMs. Terraform will update in-place. No reboot needed.
📊 TL;DR
| Resource | Terraform Property | AHB Value | Savings |
|---|---|---|---|
| Windows Server VM | license_type |
"Windows_Server" |
~38% |
| SQL Server on VM | sql_license_type |
"AHUB" |
40-55% |
| Azure SQL Database | license_type |
"BasePrice" |
~30% |
| SQL Elastic Pool | license_type |
"BasePrice" |
~30% |
| SQL DR Replica | sql_license_type |
"DR" |
100% (free) |
The savings math for a typical Windows shop:
| VM Fleet | Without AHB/month | With AHB/month | Annual Savings |
|---|---|---|---|
| 20 x D4s_v5 Windows | $4,557 | $2,803 | $21,048 |
| 10 x D8s_v5 Windows | $4,557 | $2,803 | $21,048 |
| 5 x SQL Enterprise (D4s_v5) | $6,424 | $2,803 | $43,452 |
| Combined | $85,548/year |
Bottom line: If your company has an Enterprise Agreement with Microsoft that includes Software Assurance, you're likely entitled to Azure Hybrid Benefit right now. One property in Terraform, applied org-wide through a shared module, unlocks savings that compound across every single Windows and SQL Server workload. This is free money you're leaving on the table. 💰
Run that audit command. Count the Windows VMs without Windows_Server as the license type. Multiply each D4s_v5 by $87/month. That's money you're burning because of a missing config line. 😏
This is Part 5 of the "Save on Azure with Terraform" series. Next up: Cold Storage, Hot Savings 🧊. Automating Azure Blob Storage lifecycle policies to slash storage costs with Terraform. 💬
Top comments (0)