Terraform AzureRM Provider 5.0: Breaking Changes and Upgrade Guide
Terraform AzureRM Provider 5.0: Breaking Changes and Upgrade Guide
HashiCorp shipped AzureRM provider 5.0 on July 27, 2026 (a 5.0.1 patch followed shortly after), and it's not a routine version bump. If your Terraform configs have been running fine against 4.x for months and you run terraform init -upgrade without reading anything first, there's a good chance your next terraform apply fails on a Resource Provider that quietly stopped registering itself. This walks through what actually changed and how to upgrade without breaking a pipeline.
Why this is a bigger deal than a normal major version
Provider major versions usually mean a handful of renamed arguments and a deprecation cycle you've already been warned about. AzureRM 5.0 does that too, but it also changes two behaviors that most teams never explicitly configured because the defaults just worked: automatic Azure Resource Provider (RP) registration, and pre-flight validation of locations and RPs before Azure ever sees your request. Both flip from "on by default" to "off by default." If your subscription's RPs were only ever registered because the provider did it silently on every terraform init/apply, 5.0 is the first time anyone has to think about it.
Breaking change 1: Resource Provider registration is now opt-in
Old behavior (4.x): resource_provider_registrations defaulted to "legacy", which had the provider register roughly 60 Azure Resource Providers on startup โ regardless of whether your config used them. This was slow, and it silently failed (or required elevated permissions) for anyone whose subscription access didn't include Microsoft.Authorization/*/register/action at that scope.
New behavior (5.0): the default is resource_provider_registrations = "none". Nothing gets auto-registered. If your config references a resource type under an RP that was never explicitly registered on the subscription, terraform apply fails with an RP-not-registered error โ not terraform plan, because plan doesn't touch Azure's control plane the same way.
Fix it explicitly rather than reaching for the old default:
1provider "azurerm" {
2 resource_providers_to_register = [
3 "Microsoft.Compute",
4 "Microsoft.Network",
5 "Microsoft.Storage",
6 ]
7 features {}
8}
This registers only what your config actually needs, which is also the more correct behavior for least-privilege service principals. If you need to buy time and just want 4.x behavior back while you sort out the real list:
1provider "azurerm" {
2 resource_provider_registrations = "legacy"
3 features {}
4}
Treat that as a temporary bridge, not the fix โ it re-introduces the same startup cost and permission requirement 5.0 was designed to remove.
Breaking change 2: enhanced validation moved and flipped default
Old behavior: enhanced_validation lived at the provider's top level and defaulted to validating locations and Resource Providers before terraform plan would even show you a diff โ catching typos in a location argument or a not-yet-registered RP early.
New behavior: the block moved inside features, and both location and RP validation now default to disabled. The ARM_PROVIDER_ENHANCED_VALIDATION environment variable is gone.
If you relied on that early-catch behavior (most teams did, without realizing it), re-enable it explicitly:
1provider "azurerm" {
2 features {
3 enhanced_validation {
4 locations = true
5 resource_providers = true
6 }
7 }
8}
There's also a new opt-in preflight validation mode that checks resource-level constraints (not just locations/RPs) before apply:
1provider "azurerm" {
2 features {
3 enhanced_validation {
4 preflight_enabled = true
5 preflight_location_fallback = "eastus2"
6 }
7 }
8}
Practical effect: without re-enabling validation, a typo'd region or an unregistered RP now surfaces at apply time instead of plan time โ worse for CI pipelines that gate on plan output looking clean before promoting to apply.
Breaking change 3: 40+ deprecated resources are gone, not just deprecated
5.0 removes resources that had been deprecated across several 4.x releases. If you never migrated off them, terraform init or plan will now fail outright instead of printing a warning. The ones most teams actually hit:
| Removed | Use instead |
|---|---|
azurerm_app_service | azurerm_linux_web_app / azurerm_windows_web_app |
azurerm_app_service_plan | azurerm_service_plan |
azurerm_app_service_slot | azurerm_linux_web_app_slot / azurerm_windows_web_app_slot |
azurerm_function_app | OS-specific azurerm_linux_function_app / azurerm_windows_function_app |
azurerm_postgresql_server (legacy family) | azurerm_postgresql_flexible_server |
azurerm_hpc_cache (all variants) | retired โ no direct replacement, redesign onto current storage/compute |
Property renames follow the same enable_x โ x_enabled pattern the provider has been converging on for a while โ e.g. enable_http2 is gone in favor of http2_enabled, local_authentication_disabled in favor of local_authentication_enabled. TLS minimum version arguments also stop accepting 1.0/1.1 outright.
Step-by-step upgrade process
- Pin the provider version explicitly before touching anything:
1terraform { 2 required_providers { 3 azurerm = { 4 source = "hashicorp/azurerm" 5 version = "~> 5.0" 6 } 7 } 8} - Grep your configs and modules for removed resources (the table above covers the common ones; check the full upgrade guide for anything niche like
azurerm_maps_creator). - Decide your RP registration strategy โ explicit
resource_providers_to_registerlist (recommended) vs.resource_provider_registrations = "legacy"as a stopgap. - Decide whether to re-enable enhanced/preflight validation โ if your CI gates on
plan, you probably want it back on. - Run
terraform init -upgradeandterraform planin a non-prod workspace first. Read the plan output line by line โ a clean plan with 5.0 doesn't guarantee a clean apply if RP registration is the gap, since plan doesn't hit the same code path as apply for that check. - Roll out module-by-module if you have a large monorepo, not all at once โ a single removed resource in a shared module can block every consumer of that module simultaneously.
Best practices
- Register RPs explicitly per environment, not blanket per organization โ a dev subscription and a prod subscription rarely need the same RP set, and least-privilege service principals should only get registration rights for what they use.
- Re-enable enhanced_validation in CI even if you skip it locally โ catching a bad location string at
planreview time beats catching it mid-apply in a pipeline. - Don't leave
resource_provider_registrations = "legacy"in place long-term โ it's a compatibility shim, and it reintroduces the startup latency and broad permission requirement 5.0 removed for a reason. - Audit modules you don't own (internal shared modules, third-party registry modules) separately โ they're the most common place a removed resource hides from a surface-level grep of your own root config.
Common mistakes to avoid
- Upgrading the provider and applying straight to production. The RP registration failure mode specifically doesn't show up until apply, so a "clean plan" is not sufficient evidence of a safe upgrade.
- Assuming
resource_provider_registrations = "legacy"is the permanent fix. It gets you back to 4.x behavior, including the permission requirements and startup delay that were the actual reason this changed. - Missing renamed properties in modules pulled from the public registry. Pin module versions too, not just the provider โ an unpinned community module can silently start using 5.0-only syntax underneath you.
- Skipping the non-prod dry run because "it's just a provider bump." This release specifically breaks the plan/apply parity teams rely on for safety.
Troubleshooting
If terraform apply fails with a Resource Provider not registered error after upgrading:
- Confirm the RP isn't in your
resource_providers_to_registerlist โ add it, or checkaz provider list --query "[?registrationState=='NotRegistered']"against what your config actually needs. - Confirm the identity Terraform runs as has
Microsoft.Authorization/*/register/actionat the subscription (or management group) scope โ without it, even an explicit registration list will fail. - If a plan looked clean but apply still fails, that's the expected behavior gap โ validation is off by default now, so re-enable
enhanced_validationto catch this earlier next time.
FAQ
Do I have to migrate off resource_provider_registrations = "legacy" right now?
No โ it's a supported value, not a removed one. It's a stopgap, not a deprecated setting, but it does bring back the original startup cost and broad permission requirement.
Will terraform plan catch a missing Resource Provider registration?
Not by default in 5.0. That check now happens at apply unless you explicitly re-enable enhanced_validation.resource_providers = true.
Does this affect OpenTofu users the same way?
The AzureRM provider is shared across Terraform and OpenTofu since it's a standard Terraform Registry provider, so yes โ the same breaking changes apply if you pull hashicorp/azurerm 5.x into an OpenTofu config.
Is there a way to see exactly which resources my config uses that were removed?
Run terraform init first โ it fails fast on any resource type the provider schema no longer recognizes, before you even get to plan.
What if I'm not ready to upgrade at all?
Pin to the last 4.x release (~> 4.0) in required_providers and stay there deliberately โ just don't let an unpinned >= 4.0 constraint silently pull 5.x into a build.
Key takeaways
| Area | 4.x | 5.0 |
|---|---|---|
| Resource Provider registration | Auto (~60 RPs) via legacy default | Opt-in only, explicit list recommended |
| Enhanced validation | On by default, provider-level | Off by default, moved inside features |
| Failure surfaces at | Mostly plan | RP issues now surface at apply |
| Deprecated resources | Warned, still worked | 40+ removed outright |
| Property naming | Mixed enable_x / x_enabled | Standardized on x_enabled |