Fix Azure Notification Hubs: Setup, Config & Push Errors
Why Azure Notification Hubs Stops Working
I've seen this scenario play out dozens of times: you set up Azure Notification Hubs, everything looks fine in the portal, you fire off a test notification , and nothing arrives on the device. No error. No message. Just silence. It's one of the most frustrating experiences in Azure development because the failure mode is almost always invisible at first glance.
Azure Notification Hubs sits between your app backend and the platform-specific push systems , Apple Push Notification Service (APNS), Firebase Cloud Messaging (FCM), and Windows Notification Service (WNS). That's actually the whole point of the service: instead of writing separate integration code for each of those systems, you talk to one Azure endpoint and Notification Hubs handles the fan-out. But that middle-layer position also means there are more places for things to go wrong.
Here's the core of why most Azure Notification Hubs issues happen. Each platform's push system, APNS, FCM, WNS, issues a unique, temporary device handle when your app registers for push. That handle gets stored in Notification Hubs as a "registration." When you send a message, Notification Hubs looks up the registration, calls the appropriate PNS with that handle, and the PNS delivers to the device. If any link in that chain breaks, stale handle, wrong credentials, misconfigured namespace, expired certificate, your notification disappears without a trace.
The most common root causes I see fall into four buckets:
- Wrong or expired PNS credentials, Your APNS certificate expired, your FCM server key was rotated, or your WNS client secret changed. Notification Hubs tries to call the PNS and gets rejected silently.
- Stale device registrations, Per PNS guidelines, device tokens must be refreshed on every app launch. If your client app isn't re-registering on startup, handles go stale and deliveries fail.
- Connection string misconfiguration, Your backend is connecting with the Listen-only connection string instead of the Full Access (send) connection string, or pointing at the wrong namespace entirely.
- Tag and routing mismatches, You're sending to a tag that no device is actually registered with, or the tag expression syntax is wrong and the query returns zero devices.
Microsoft's error messages in this area are genuinely unhelpful. You'll get generic HTTP 400s or 401s in your SDK logs with no clear pointer to which credential is wrong or which registration is stale. I know this is frustrating, especially when you have a production app blocked. Let's fix it systematically. Browse all Microsoft fix guides →
The Quick Fix, Try This First
Before diving deep, run through this fast checklist. Roughly 60% of Azure Notification Hubs problems I've seen get resolved at this stage, usually within ten minutes.
Open the Azure portal and navigate to your notification hub. In the left sidebar, look for Settings > Access Policies. You'll see two connection strings: DefaultListenSharedAccessSignature and DefaultFullSharedAccessSignature. Your backend server must use the Full Access string to send notifications. Your client app should use the Listen-only string to register. Swapping these is the single most common mistake, and it produces a 401 Unauthorized that's easy to miss in SDK logs.
Copy your Full Access connection string and compare it character-for-character against what's in your backend config. Pay attention to the hub name embedded in the string, it looks like Endpoint=sb://YOUR-NAMESPACE.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=YOURKEY==. If the namespace or hub name is wrong, requests go to a nonexistent endpoint.
Next, navigate to Settings > Apple (APNS), Settings > Google (FCM), or Settings > Windows (WNS), whichever platform you're targeting. Check when certificates or keys were last updated. APNS certificates issued through the Apple Developer portal expire annually. If yours expired even one day ago, every iOS push silently fails. FCM API keys don't expire, but they can be revoked in the Google Cloud Console, check that the key hasn't been restricted or deleted.
Finally, use the Test Send feature built right into the portal: go to your hub, click Test Send in the left sidebar, pick your platform, and send a direct notification to a specific device registration ID you know is live. If this works, your hub configuration is fine and the problem is in your backend code. If it fails, you'll see an actual error message that points you to the right layer.
If you're starting fresh or suspect your hub was created incorrectly, let's verify the basics. In the Azure portal, go to Create a resource, search for "Notification Hubs," and click Create. You'll need to create or select a Notification Hubs namespace first, think of the namespace as the container, and the hub as the specific channel for one app. The naming matters: namespace names must be globally unique across Azure, and once created they can't be renamed.
Select your Pricing Tier carefully. The Free tier limits you to 500 active devices and 1 million pushes per month with no SLA. The Basic tier gives you 200,000 active devices. The Standard tier removes device caps and adds scheduled push, broadcast segmentation, and telemetry, you need Standard if you're doing anything beyond a proof-of-concept. If you're seeing a QuotaExceeded error, this is almost always the cause.
After creation, navigate to your hub and verify the Overview blade shows your hub's name, namespace, and region. Write down the exact hub name, even a single character difference between what the portal shows and what your SDK is configured with causes a 404 Not Found on every send attempt.
To verify your hub is reachable, run this quick PowerShell connectivity test:
# Test namespace reachability
$namespaceName = "your-namespace"
$hubName = "your-hub"
Test-NetConnection -ComputerName "$namespaceName.servicebus.windows.net" -Port 443
You should see TcpTestSucceeded : True. If not, a firewall or network policy is blocking outbound HTTPS to Service Bus endpoints, that needs to be fixed at the network level before anything else will work.
This step is where most Azure Notification Hubs configuration errors live. Each mobile platform has its own push infrastructure, and each one requires specific credentials entered into Notification Hubs before it can forward messages on your behalf.
For iOS (APNS): Navigate to Settings > Apple (APNS) in your hub. You have two authentication options, Certificate (.p12 file) or Token-based auth (.p8 key). Token-based is strongly preferred because certificates expire yearly. If you're using a certificate, check the expiry date right now: open the .p12 in Keychain Access on a Mac and look for the expiration field. Expired certificates give you no warning in Notification Hubs, they just silently fail. Token-based auth requires your Key ID, Team ID, and the .p8 private key file from the Apple Developer portal under Certificates, Identifiers & Profiles > Keys.
For Android (FCM): Go to Settings > Google (FCM/FCMv1). Google deprecated the legacy FCM HTTP API and migrated to FCM v1, if you're still using a Server Key from the old console, you need to migrate to FCM v1 using a Google Service Account JSON file. In the portal, upload the service account JSON under the FCMv1 section. You can generate this JSON in the Google Cloud Console > IAM & Admin > Service Accounts.
For Windows (WNS): Go to Settings > Windows (WNS) and enter your Package SID and Client Secret from the Microsoft Partner Center under your app's registration. These rotate if you regenerate secrets in Partner Center, always sync both places when you do.
After saving credentials, use Test Send to confirm each platform accepts the connection. A successful test confirms credentials are valid. A 401 on test send means the credentials themselves are wrong or expired, go back to the source (Apple Developer portal, Google Cloud Console, Microsoft Partner Center) and regenerate fresh credentials.
Here's something that trips up a lot of developers: device registrations in Azure Notification Hubs aren't permanent. Each time a user launches your app, the PNS may issue a new device handle (token). Your app must re-register that new handle with Notification Hubs on every launch, not just at install time. If you're only registering once at install and never updating, within days or weeks your registrations go stale and pushes fail silently.
The correct pattern is: on app launch, request a fresh PNS token from the OS, then call Notification Hubs to create or update the registration with that token. In the .NET SDK this looks like:
// Get fresh PNS token from platform
var token = await GetFreshDeviceTokenFromPNS();
// Register or update with Notification Hubs
var hub = NotificationHubClient.CreateClientFromConnectionString(
connectionString, hubName);
// Upsert: creates if not exists, updates if handle changed
var registration = await hub.CreateOrUpdateRegistrationAsync(
new FcmV1RegistrationDescription(token)
{
Tags = new HashSet<string> { "userId:12345", "region:us-west" }
});
If you're seeing a 410 Gone response from the PNS when Notification Hubs tries to deliver, that means the stored handle is dead. The hub automatically removes the registration after a 410, but the registration existed long enough that your send attempt failed for that device. The fix is enforcing re-registration at every app open.
To audit your current registrations and find stale ones, use the Azure CLI:
az notification-hub registration list \
--resource-group myResourceGroup \
--namespace-name myNamespace \
--notification-hub-name myHub \
--query "[?expirationTime < '2026-04-21']"
Any registration with a past expirationTime is stale and should be pruned. Clean these out to keep your active device count accurate, especially if you're approaching tier limits.
When a push notification disappears and you don't know why, Azure Notification Hubs telemetry is your best friend, but you have to know where to look. Navigate to your hub in the portal, then click Monitoring > Metrics. The key metrics to check are:
- Outgoing Notifications, total sends attempted from the hub to the PNS
- Successful Notifications, what the PNS accepted
- PNS Errors, rejections from Apple, Google, or Microsoft's push systems
- Bad Channel Errors, stale or invalid device handles
If Outgoing equals Successful but the device didn't receive the notification, the problem is downstream of Notification Hubs, it's in the PNS or on the device itself (app not running, Do Not Disturb, battery optimization killing the process). If PNS Errors are high, your credentials are bad. If Bad Channel Errors are climbing, you have stale registrations.
For per-message debugging, enable Notification Hub Message Log. This is only available on the Standard tier. Go to Support + Troubleshooting > Message Log. Each message shows the outcome: Delivered, Dropped, PNSError, or Expired. The PNSError entries include the raw error code from the PNS, for example, APNS error code BadDeviceToken tells you immediately the handle is stale.
You can also pull diagnostic logs into Log Analytics. In Monitoring > Diagnostic Settings, add a setting to stream OperationalLogs to a Log Analytics workspace. Then query them:
AzureDiagnostics
| where ResourceType == "NOTIFICATIONHUBS"
| where OperationName == "NotificationHubPushNotificationResult"
| where ResultType == "Failed"
| project TimeGenerated, HubName, ErrorCode, ErrorDescription
| order by TimeGenerated desc
This surfaces real-time failures with actionable error descriptions, far more useful than watching the metrics graph. If you see InvalidCredential in the ErrorCode column, your PNS credentials have drifted.
Azure Notification Hubs uses a tag system to route messages to specific groups of devices. A tag is just a string, like userId:42, topic:sports, or region:europe, that you attach to a device registration. When you send, you specify a tag expression and only devices whose registrations match get the message. This is one of the most powerful features of the service, and also one of the most common sources of confusion when nothing is delivered.
The most common tagging mistake: sending to a tag that no device is actually registered with. Before debugging anything else, verify registrations have the tag you're targeting:
az notification-hub registration list \
--resource-group myRG \
--namespace-name myNS \
--notification-hub-name myHub \
--query "[?contains(tags, 'userId:42')]"
If that returns an empty array, no device has that tag. Check your client registration code and confirm it's passing the correct tag strings when it calls Notification Hubs to register.
Tag expressions support Boolean logic: && (AND), || (OR), and ! (NOT). An expression like active && region:seattle && !new_user is valid and powerful, but if the expression is syntactically wrong you'll get an HTTP 400 with InvalidTagExpression. Test expressions with the portal's Test Send blade before deploying to your backend.
Template registrations are the other major piece here. Templates let individual devices define their own notification format, so an iOS device can use APNS JSON and an Android device can use FCM JSON, but you send one generic message from your backend. If template pushes aren't arriving, check that your template body uses the correct substitution variable syntax: $(variableName). A mismatch between variable names in the template and in your send payload results in a silently dropped message. Always send a template notification payload that includes values for every $(variable) defined in the template, missing variables cause the message to be dropped without an error.
Advanced Azure Notification Hubs Troubleshooting
If the steps above didn't resolve your issue, you're likely dealing with something at the network, enterprise configuration, or SDK version level. Here's how to go deeper.
Network and Firewall Rules for Azure Notification Hubs
Notification Hubs communicates with PNS endpoints over HTTPS (port 443). If your backend runs in a locked-down corporate network or Azure VNET with strict egress rules, outbound traffic to Apple, Google, and Microsoft push endpoints must be explicitly allowed. APNS uses api.push.apple.com (port 443 and 2197). FCMv1 uses fcm.googleapis.com (port 443). WNS uses *.notify.windows.com (port 443).
Your Azure backend also needs to reach the Service Bus endpoints for Notification Hubs itself: *.servicebus.windows.net on port 443. If your VNET has a Network Security Group (NSG) blocking outbound traffic, add rules for the ServiceBus Azure service tag:
az network nsg rule create \
--resource-group myRG \
--nsg-name myNSG \
--name AllowServiceBusOutbound \
--protocol Tcp \
--direction Outbound \
--destination-service-tag ServiceBus \
--destination-port-ranges 443 \
--priority 200 \
--access Allow
SDK Version Mismatches and Deprecated APIs
The Microsoft.Azure.NotificationHubs NuGet package has gone through several breaking changes. If you're on a version older than 4.x, you may be calling deprecated registration endpoints that behave differently. Check your version:
dotnet list package | grep "Microsoft.Azure.NotificationHubs"
If you're below 4.0.0, update: dotnet add package Microsoft.Azure.NotificationHubs. The FCMv1 migration in particular requires SDK 4.1.0 or higher, older versions only support the deprecated FCM legacy API which Google has fully shut down.
Enterprise and Managed Identity Authentication
In enterprise environments, hardcoding Shared Access Signatures in config files is a security risk. Azure Notification Hubs supports Azure Active Directory authentication via Managed Identity. Assign the Azure Notification Hubs Data Contributor role to your app's managed identity in Access Control (IAM) on the hub resource, then authenticate without any connection string:
var credential = new DefaultAzureCredential();
var hub = new NotificationHubClient(
new Uri("https://your-namespace.servicebus.windows.net/your-hub"),
credential);
If Managed Identity auth fails with AuthorizationFailed, the role assignment hasn't propagated yet, wait up to 5 minutes after assigning the role before testing.
Diagnosing Broadcast Failures at Scale
Sending to millions of devices through a single API call is one of Notification Hubs' core capabilities, but large broadcasts take time to fan out. The send API returns a NotificationOutcome with a tracking ID, poll for final results using:
var outcome = await hub.SendBroadcastNotificationAsync(notification);
// outcome.TrackingId is your reference for checking results later
var results = await hub.GetNotificationOutcomeDetailsAsync(outcome.NotificationId);
If you're seeing partial delivery on large broadcasts, check the Standard tier is active, the Free and Basic tiers throttle broadcast throughput aggressively.
Prevention & Best Practices for Azure Notification Hubs
Once you've fixed the immediate issue, here's how to keep Azure Notification Hubs running smoothly long-term. Most of these are things I wish someone had told me before the first production outage.
Re-register devices on every app launch. I said this earlier but it bears repeating because it's the single biggest cause of silent delivery failures over time. Build re-registration into your app's startup sequence, not just your install flow. Treat the PNS token as potentially stale every single time.
Automate PNS credential monitoring. APNS certificates expire with zero warning from Azure. Set a calendar reminder 60 days before your current certificate expires to generate a new one in the Apple Developer portal and upload it. Better yet, switch to token-based APNS authentication, .p8 keys don't expire, which eliminates an entire failure mode.
Set up Azure Monitor alerts. Go to Monitoring > Alerts in your hub and create alerts for: PNS Error rate exceeding 1%, Bad Channel Error rate exceeding 5%, and Notification Hub throttling events. These alerts give you early warning before users start reporting missed notifications.
Tag your registrations with version and install date. Adding tags like appVersion:2.4 and installYear:2026 to registrations gives you the ability to target or exclude specific cohorts. It also lets you clean up old registrations, anything with installYear:2023 and no recent activity is almost certainly from an uninstalled app.
Test across all target platforms before each release. A change that works fine for Android FCMv1 delivery might expose a stale APNS certificate you haven't touched. Build a pre-release checklist that includes a Test Send to a real device on every supported platform.
- Switch APNS authentication from certificate to token-based (.p8) to eliminate annual certificate expiry failures
- Enable Message Log on Standard tier, the per-message outcome data is invaluable for diagnosing sporadic delivery failures
- Use Managed Identity instead of connection string secrets in production backends, eliminates credential rotation as a failure point
- Add an Azure Monitor alert for Bad Channel Error rate > 5% so stale registration buildup gets flagged before it compounds
Frequently Asked Questions
What exactly is Azure Notification Hubs and how is it different from sending push notifications directly?
Azure Notification Hubs is a managed push engine that sits between your app backend and each platform's native push system, Apple's APNS, Google's FCM, and Microsoft's WNS. Without it, your backend has to talk to each of those systems separately, manage credentials for each, and write platform-specific code for every notification type. Notification Hubs gives you one API endpoint and handles the fan-out to whatever platforms your users are on. The real win is at scale: broadcasting to a million devices across iOS, Android, and Windows in a single API call is something that would take massive infrastructure to build yourself, here it's just a method call.
What are push notifications and why do they sometimes not show up on my device?
Push notifications are messages your app backend sends to a user's device even when the app isn't open, they show up as banners, badges, or sounds depending on how the user has configured app permissions. When they don't arrive, the failure is almost always in one of three places: the device handle stored in Notification Hubs is stale (the OS issued a new token and your app didn't re-register it), the PNS credentials in your hub are expired or revoked, or the device itself is blocking delivery through battery optimization, Do Not Disturb, or revoked notification permissions. The portal's Test Send feature is the fastest way to isolate which layer is failing.
How do push notifications actually work through Azure Notification Hubs step by step?
Here's the flow: first, your mobile app asks the device OS for a push handle, a unique token issued by APNS, FCM, or WNS. The app sends that token to your backend (or directly to Notification Hubs) to create a registration. When you want to send a notification, your backend calls the Notification Hubs API with the message and targeting info (a specific device, a tag, or a broadcast). Notification Hubs looks up the matching registrations, formats the payload for each platform's requirements, and calls each PNS with the appropriate handle. The PNS then delivers the message to the device. Every step in that chain has to be working for the notification to land.
Why should I use Azure Notification Hubs instead of calling FCM or APNS directly?
The short answer is scale and sanity. Calling FCM and APNS directly is manageable when you have hundreds of users, but when you're dealing with tens of thousands of devices, you need to handle token refresh cycles, build retry logic, maintain a device registry, manage platform-specific payload formatting, and implement segmentation logic yourself. That's a significant engineering investment that has nothing to do with your actual product. Notification Hubs handles device handle management, multi-platform delivery, tag-based segmentation, scheduled sends, and telemetry out of the box. You focus on what you want to say; it figures out how to deliver it to the right people on the right platform.
My Azure Notification Hubs test send works but real notifications from my backend don't, what's wrong?
This is one of the clearest diagnostic signals you can get, actually. Test Send in the portal calls the hub with admin-level credentials directly, so if it works, your hub configuration, PNS credentials, and device registration are all fine. The problem is in your backend. The most common cause is using the Listen-only connection string (DefaultListenSharedAccessSignature) in your backend code instead of the Full Access string (DefaultFullSharedAccessSignature), Listen-only doesn't have send permission. The second most common cause is the wrong hub name or namespace in your connection string. Double-check both of those first.
How do I handle the FCM to FCMv1 migration in Azure Notification Hubs?
Google shut down the legacy FCM HTTP API, so if you're still configured with an old Server Key in Notification Hubs, your Android pushes are failing entirely. To migrate: go to the Google Cloud Console, create a Service Account under IAM & Admin > Service Accounts, grant it the Firebase Cloud Messaging API Admin role, and download the JSON key file. Then in the Azure portal go to your hub's Settings > Google (FCMv1) and upload that JSON file. On the SDK side, update to Microsoft.Azure.NotificationHubs version 4.1.0 or higher and replace any FcmRegistrationDescription calls with FcmV1RegistrationDescription. Existing legacy registrations need to be re-registered under the new FCMv1 type, you can't migrate them in place.