You deploy your Xperience by Kentico instance to Azure App Service, everything looks fine, and then — queries start failing. Tables that should exist apparently don’t. But when you check the database, the tables are there. So what’s going on?

The tables were created under the db_owner schema instead of dbo.

The Symptom

After deploying a Xperience by Kentico application to an Azure App Service with an Azure SQL Database, custom module tables (in our case, from the Tag Manager integration) were not being found by the application. SQL errors indicated that tables like KenticoTagManager_ChannelCodeSnippetItem did not exist — even though they were clearly present in the database.

The catch: the tables existed as db_owner.KenticoTagManager_ChannelCodeSnippetItem instead of the expected dbo.KenticoTagManager_ChannelCodeSnippetItem.

The Root Cause: SQL Server Default Schema Behavior

When SQL Server executes a CREATE TABLE statement without an explicit schema qualifier (e.g., CREATE TABLE MyTable instead of CREATE TABLE dbo.MyTable), it uses the default schema of the executing user.

Xperience by Kentico — like most ORMs and frameworks — creates tables without schema qualification. This is standard behavior, and it works perfectly as long as the SQL user’s default schema is dbo.

Here’s where Azure SQL Database introduces a subtle gotcha.

How Azure SQL Users Are Typically Created

When provisioning an Azure SQL Database, it’s common to create a contained database user like this:

CREATE USER [myappuser] WITH PASSWORD = 'SomeSecurePassword';
ALTER ROLE db_owner ADD MEMBER [myappuser];

This gives the user full permissions — but does not set a default schema. In SQL Server, when a user has no explicit default schema and is a member of the db_owner role, the engine falls back to using db_owner as the default schema.

So every CREATE TABLE issued by Kentico’s DataEngine during module installation silently goes to the db_owner schema instead of dbo.

Why It Works Locally But Fails in Azure

Locally, you’re likely connecting with sa, Windows Authentication, or a SQL user that already has dbo as its default schema. That’s why the issue never surfaces in development — the tables land in dbo as expected.

It’s only in Azure (or any environment where the SQL user lacks an explicit default schema) that the problem appears.

How to Diagnose

Step 1: Identify the SQL User

Find the connection string your App Service uses. In the Azure Portal, go to your App Service > Configuration (or Environment variables) and look at the connection string. The User ID= value is the SQL user you need to check.

Step 2: Check the User’s Default Schema

Connect to your Azure SQL Database (via the Azure Portal Query Editor, SSMS, or Azure Data Studio) and run:

SELECT
    name,
    default_schema_name,
    type_desc
FROM sys.database_principals
WHERE name = 'your_sql_user';

If default_schema_name is db_owner (or NULL), you’ve found the problem.

Step 3: Verify Where the Tables Ended Up

SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'KenticoTagManager%';

If the TABLE_SCHEMA column shows db_owner instead of dbo, that confirms it.

How to Fix It

1. Set the User’s Default Schema to dbo

ALTER USER [your_sql_user] WITH DEFAULT_SCHEMA = dbo;

2. Move Existing Tables to the Correct Schema

For the Tag Manager integration specifically:

ALTER SCHEMA dbo TRANSFER db_owner.KenticoTagManager_ChannelCodeSnippetItem;
ALTER SCHEMA dbo TRANSFER db_owner.KenticoTagManager_ChannelCodeSnippetItemContentType;

For other modules or custom tables, adjust the table names accordingly. You can find all misplaced tables with:

SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'db_owner';

And transfer them all:

-- Generate transfer statements for all tables in the wrong schema
SELECT 'ALTER SCHEMA dbo TRANSFER db_owner.' + QUOTENAME(TABLE_NAME) + ';'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'db_owner';

3. Verify the Fix

Run the table schema query again to confirm all tables are now under dbo:

SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'KenticoTagManager%';

How to Prevent It

When creating SQL users for your Xperience by Kentico database in Azure SQL, always explicitly set the default schema:

CREATE USER [myappuser] WITH PASSWORD = 'SomeSecurePassword', DEFAULT_SCHEMA = dbo;
ALTER ROLE db_owner ADD MEMBER [myappuser];

The key addition is DEFAULT_SCHEMA = dbo in the CREATE USER statement.

If the user already exists, you can set it retroactively:

ALTER USER [myappuser] WITH DEFAULT_SCHEMA = dbo;

Important Note

This is not specific to the Tag Manager integration. This affects any Xperience by Kentico module — built-in or custom — that creates database tables during installation. The Kentico DataEngine, like most frameworks, creates tables without schema qualification and relies on the SQL user having dbo as its default schema.

If you’re deploying Xperience by Kentico to Azure SQL Database, verifying the SQL user’s default schema should be part of your deployment checklist.