Click here to Skip to main content
Click here to Skip to main content

Minimum Database Permissions Required for SqlDependency

By , 22 Mar 2006
 

Introduction

.NET 2.0 has a cool new feature called SqlDependency which provides a mechanism to notify an application when a cache is invalidated. We're not going to go explain the use of this technology in this article because there are plenty of good resources already available like this one. This article is going to show you what minimum rights a SQL Server 2005 user should have for SqlDependency to work. Sushil Cordia has a blog on MSDN that describes most of these rights, but I have noticed that this blog doesn't list all rights required. Hence, this article.

Using the Code

There are two pieces of code that accompany this article. The first is a SQL Script that sets the necessary permissions; the other is a C# console application that uses SqlDependency to watch for changes in a specific table.

My original idea was to create two roles in SQL Server that have all the permissions required to run SQLDependency; one role that has all the permissions to start the SqlDependency listener and the other that has the permissions required to subscribe for changes. However, I have noticed that this is not possible. The problem with having only two roles is that the users that are members of these roles will belong to the dbo-schema. This causes problems when trying to run SqlDependency.Start because this method attempts to create a queue in the schema of the user and it doesn't have sufficient rights to do so. Therefore, the solution mentioned in this article creates these two roles containing the required permissions, but you should also make sure that the user that starts SqlDependency has its own schema of which it is the owner.

The following is the SQL Script that does the following:

  • Creates a test database called SqlDependencyTest
  • Creates a user called startUser which is a user that will have sufficient rights to call SqlDependency.Start
  • Creates a user called subscribeUser which is a user that will have sufficient rights to subscribe for change notifications
  • Creates a role called sql_dependency_starter that has some permissions set that gives all the members of this role sufficient rights to run SqlDependency.Start
  • Creates a role called sql_dependency_subscriber that has some permissions set that gives all the members of this role sufficient rights to subscribe for notifications.
USE master

-- Cleaning up before we start
IF  EXISTS (SELECT name FROM sys.databases WHERE name = N'SqlDependencyTest')
DROP DATABASE [SqlDependencyTest]
IF  EXISTS (SELECT * FROM sys.server_principals WHERE name = N'startUser')
DROP LOGIN [startUser]
IF  EXISTS (SELECT * FROM sys.server_principals WHERE name = N'subscribeUser')
DROP LOGIN [subscribeUser]

-- Creating a database
CREATE DATABASE [SqlDependencyTest]
GO

-- Ensuring that Service Broker is enabled 
ALTER DATABASE [SqlDependencyTest] SET ENABLE_BROKER
GO 

-- Creating users
CREATE LOGIN [startUser] WITH PASSWORD=N'startUser', 
            DEFAULT_DATABASE=[SqlDependencyTest], 
            CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
CREATE LOGIN [subscribeUser] WITH PASSWORD=N'subscribeUser', 
            DEFAULT_DATABASE=[SqlDependencyTest], CHECK_EXPIRATION=OFF, 
            CHECK_POLICY=OFF
GO

-- Switching to our database
use [SqlDependencyTest]

-- Creating a table. All changes made to the contents of this table will be
-- monitored.
CREATE TABLE Users (ID int, Name nvarchar(50))
GO

/*
 * Creating the users in this database
 *
 * We're going to create two users. One called startUser. This is the user 
 * that is going to have sufficient rights to run SqlDependency.Start.
 * The other user is called subscribeUser, and this is the user that is 
 * going to actually register for changes on the Users-table created earlier.
 * Technically, you're not obligated to make two different users naturally, 
 * but I did here anyway to make sure that I know the minimal rights required
 * for both operations
 *
 * Pay attention to the fact that the startUser-user has a default schema set.
 * This is critical for SqlDependency.Start to work. Below is explained why.
 */
CREATE USER [startUser] FOR LOGIN [startUser] 
WITH DEFAULT_SCHEMA = [startUser]
GO
CREATE USER [subscribeUser] FOR LOGIN [subscribeUser]
GO

/*
 * Creating the schema
 *
 * It is vital that we create a schema specifically for startUser and that we
 * make this user the owner of this schema. We also need to make sure that 
 * the default schema of this user is set to this new schema (we have done 
 * this earlier)
 *
 * If we wouldn't do this, then SqlDependency.Start would attempt to create 
 * some queues and stored procedures in the user's default schema which is
 * dbo. This would fail since startUser does not have sufficient rights to 
 * control the dbo-schema. Since we want to know the minimum rights startUser
 * needs to run SqlDependency.Start, we don't want to give him dbo priviliges.
 * Creating a separate schema ensures that SqlDependency.Start can create the
 * necessary objects inside this startUser schema without compromising 
 * security.
 */
CREATE SCHEMA [startUser] AUTHORIZATION [startUser]
GO

/*
 * Creating two new roles. We're not going to set the necessary permissions 
 * on the user-accounts, but we're going to set them on these two new roles.
 * At the end of this script, we're simply going to make our two users 
 * members of these roles.
 */
EXEC sp_addrole 'sql_dependency_subscriber' 
EXEC sp_addrole 'sql_dependency_starter' 

-- Permissions needed for [sql_dependency_starter]
GRANT CREATE PROCEDURE to [sql_dependency_starter] 
GRANT CREATE QUEUE to [sql_dependency_starter]
GRANT CREATE SERVICE to [sql_dependency_starter]
GRANT REFERENCES on 
CONTRACT::[http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]
  to [sql_dependency_starter] 
GRANT VIEW DEFINITION TO [sql_dependency_starter] 

-- Permissions needed for [sql_dependency_subscriber] 
GRANT SELECT to [sql_dependency_subscriber] 
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO [sql_dependency_subscriber] 
GRANT RECEIVE ON QueryNotificationErrorsQueue TO [sql_dependency_subscriber] 
GRANT REFERENCES on 
CONTRACT::[http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]
  to [sql_dependency_subscriber] 

-- Making sure that my users are member of the correct role.
EXEC sp_addrolemember 'sql_dependency_starter', 'startUser'
EXEC sp_addrolemember 'sql_dependency_subscriber', 'subscribeUser'

All we need now is a test application that uses these two users and ensures that SqlDependency works:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text;

namespace SqlDependencyTest
{
  class Program
  {
    private static string mStarterConnectionString = 
@"Data Source=(local);Database=SqlDependencyTest;Persist Security Info=false;
  Integrated Security=false;User Id=startUser;Password=startUser";
    private static string mSubscriberConnectionString = 
@"Data Source=(local);Database=SqlDependencyTest;Persist Security Info=false;
Integrated Security=false;User Id=subscribeUser;Password=subscribeUser";

    static void Main(string[] args)
    {
      // Starting the listener infrastructure...
      SqlDependency.Start(mStarterConnectionString);

      // Registering for changes... 
      RegisterForChanges();

      // Waiting...
      Console.WriteLine("At this point, you should start the Sql Server ");
      Console.WriteLine("Management Studio and make ");
      Console.WriteLine("some changes to the Users table that you'll find");
      Console.WriteLine(" in the SqlDependencyTest ");
      Console.WriteLine("database. Every time a change happens in this ");
      Console.WriteLine("table, this program should be ");
      Console.WriteLine("notified.\n");
      Console.WriteLine("Press enter to quit this program.");
      Console.ReadLine();

      // Quitting...
      SqlDependency.Stop(mStarterConnectionString);
    }

    public static void RegisterForChanges()
    {
      // Connecting to the database using our subscriber connection string 
      // and waiting for changes...
      SqlConnection oConnection 
                          = new SqlConnection(mSubscriberConnectionString);
      oConnection.Open();
      try
      {
        SqlCommand oCommand = new SqlCommand(
          "SELECT ID, Name FROM dbo.Users",
          oConnection);
        SqlDependency oDependency = new SqlDependency(oCommand);
        oDependency.OnChange += new OnChangeEventHandler(OnNotificationChange);
        SqlDataReader objReader = oCommand.ExecuteReader();
        try
        {
          while (objReader.Read())
          {
            // Doing something here...
          }
        }
        finally
        {
          objReader.Close();
        }
      }
      finally
      {
        oConnection.Close();
      }
    }

    public static void OnNotificationChange(object caller, 
                                            SqlNotificationEventArgs e)
    {
      Console.WriteLine(e.Info.ToString() + ": " + e.Type.ToString());
      RegisterForChanges();
    }
  }
}

Points of Interest

Many thanks to my Microsoft buddy, Nicole Haugen, for helping me solve some of the problems encountered.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Michael Vanhoutte
Team Leader
Belgium Belgium
Member
I am a developer spending most of my time in C#, .NET 2.0 and Sql Server 2005. I am working for a Belgium company called Adam Software developing Asset Management Software. More information about my company and our software can be found at http://www.adamsoftware.net

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberEdo Tzumer27 Nov '12 - 23:41 
The "little (but sometimes most important) things"
QuestionWhy is this not on MSDN?memberL8Again27 Oct '11 - 23:46 
I literally wasted 2 days trying to get SQLCacheDependency to work on an ASP.NET application. Even though this article doesn't speak to that directly, it helped me more than any article anywhere. Most complete and succinct example I have seen on the subject so far. Keep up the good work.
GeneralMy vote of 5memberzeekiorage19 Oct '10 - 12:38 
Excellent example
GeneralTrouble when changed to Stored ProcedurememberRick Weyrauch29 Jan '10 - 3:54 
I was able to run my app with the setup you suggested - THANKS!!
 
One problem I am having is that I need to use Stored Procedures for all my DB access calls. I added "GRANT EXECUTE to [sql_dependency_subscriber]" to your script attempting to give the subscriber access to run sprocs but I always get back an e.Info of "Invalid". My sproc was very simple:
 
CREATE PROCEDURE SelectAllUsers 
AS
BEGIN
	SET NOCOUNT ON;
 
	SELECT ID, Name from dbo.Users
END
GO
Any chance you have some idea on why that would be?
 
Also, is there a way to know why the result was Invalid? I can not seem to find any trace of exactly what went wrong.
 
Rick
GeneralRe: Trouble when changed to Stored ProcedurememberRick Weyrauch29 Jan '10 - 4:08 
I found my own answer: You can not use this statement in the sproc.
SET NOCOUNT ON
I removed it and everything is fine now.
Questionsqldependency in win formsmembersnaveenkumareee29 Dec '08 - 1:43 
Hi Micheal,
the article has helped a lot. thanks..
 
Please advise for my requirement. i got a requirement of sqldependency on a table in win forms application. can i use this sqldependency. Does sqlDependency.Start() maintains a live database connection ??
 
Thanks
Naveen S
AnswerRe: sqldependency in win formsmemberMichael Vanhoutte30 Dec '08 - 4:04 
Yes this feature should also work in WinForms and yes it does keep a live database connection while it's waiting for events.
QuestionGetting an error while starting SqlDependencymemberSamnang Chhun6 May '08 - 16:25 
Hi,
 
When I try to follow your example in the article, I get an error while starting SqlDependency ( SqlDependency.Start(mStarterConnectionString)).
 
The error is :
 
A connection was successfully established with the server, but then an error occurred during the login process. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)
 
Thanks,
Samnang
Questionwhat if the database user already exists?memberlax4u7 Apr '08 - 11:52 
I want to enable sql server notification on existing database user which has execute permission on some stored procedures? i did accordingly but now i get following error
A connection was successfully established with the server, but then an error occurred during the login process. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)
 
consider user is 'username' and database is 'databasename'
------------------------------------------------------
use [master]
Go
 
-- Ensuring that Service Broker is enabled
ALTER DATABASE [DatabaseName] SET ENABLE_BROKER
GO
 
-- Switching to our database
use [DatabaseName]
GO
 
CREATE SCHEMA username AUTHORIZATION username
GO
 
ALTER USER username WITH DEFAULT_SCHEMA = username
GO
 
/*
* Creating two new roles. We're not going to set the necessary permissions
* on the user-accounts, but we're going to set them on these two new roles.
* At the end of this script, we're simply going to make our two users
* members of these roles.
*/
EXEC sp_addrole 'sql_dependency_subscriber'
EXEC sp_addrole 'sql_dependency_starter'
 
-- Permissions needed for [sql_dependency_starter]
GRANT CREATE PROCEDURE to [sql_dependency_starter]
GRANT CREATE QUEUE to [sql_dependency_starter]
GRANT CREATE SERVICE to [sql_dependency_starter]
GRANT REFERENCES on
CONTRACT::[http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]
to [sql_dependency_starter]
GRANT VIEW DEFINITION TO [sql_dependency_starter]
 
-- Permissions needed for [sql_dependency_subscriber]
GRANT SELECT to [sql_dependency_subscriber]
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO [sql_dependency_subscriber]
GRANT RECEIVE ON QueryNotificationErrorsQueue TO [sql_dependency_subscriber]
GRANT REFERENCES on
CONTRACT::[http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]
to [sql_dependency_subscriber]
 
-- Making sure that my users are member of the correct role.
EXEC sp_addrolemember 'sql_dependency_starter', 'username'
EXEC sp_addrolemember 'sql_dependency_subscriber', 'username'
AnswerRe: what if the database user already exists?memberMichael Vanhoutte15 Apr '08 - 8:43 
Not really sure what is causing this, but don't really think it's related to Service Broker. You might try searching in blogs like http://blogs.msdn.com/sql_protocols/archive/2005/09/22/473012.aspx[^]. They sometimes contain information that could help.
GeneralIn my case, both users set their default schema to dbo, but still get no permission logged,memberwyx200031 Mar '08 - 13:19 
The query notification dialog on conversation handle '{A79C2690-65FF-DC11-A4E1-000D5670268E}.' closed due to the following error: '<?xml version="1.0"?><Error xmlns="http://schemas.microsoft.com/SQL/ServiceBroker/Error"><Code>-8494</Code><Description>You do not have permission to access the service &apos;SqlQueryNotificationService-2424d027-3faa-4b1a-95a5-95f0a3636b62&apos;.</Description></Error>'.
Generalsql_dependency_subscriber is this a special rolememberMilind Y27 Mar '08 - 20:16 
what if I create only one role called application_sql_dependency role and assign all the permission required for sender and subscriber. Will this work? reason behing this I want run my ASP.NET web application under only one windows account which is added to the application_sql_dependency databse role. I guess giving required permissions to this role will do the job. Please let me know.
GeneralRe: sql_dependency_subscriber is this a special rolememberMichael Vanhoutte3 Apr '08 - 20:51 
No, don't think it will. My comments state:
* It is vital that we create a schema specifically for startUser and that we
* make this user the owner of this schema. We also need to make sure that
* the default schema of this user is set to this new schema (we have done
* this earlier)
 
if you simply create a role for both users and not the schema for the start-user, then it won't work.
GeneralHelped a lot, and there's a bug in SQL Server with itmemberMartin Sp.24 Jan '08 - 7:02 
First of all, thanks for your article. It helps a lot. All examples except this works only for an admin account like sa, but I needed a solution for accounts with restricted rights.
 
And second, it looks like noone from MS tested it with restricted logins. If you call SqlDependency.Start( connString ) with the startUser you mentioned, but don't call SqlDependency.Stop( connString ), the following happens: SQL Server 2005 recognizes the loss of the connection, and starts a timer trying to clean up. Unfortunately, the stored procedure which was created during SqlDependency.Start() doesn't include the schema for the service. So the service can't be cleaned, the stored procedure fails, and an entry in the SQL Server log is written. The message of this entry is of no use, telling there's no text for the stored procedure in syscomments D'Oh! | :doh:
 
And then the timer comes back, tries the same thing again. And again. Several times a seconds. In effect, you will find a lot of entries in the SQL Server log. Far more than the protocol viewer of SQL Server Managment Studio can handle. It shows an OutOfMemoryException.
 
To make things even more worse, imagine there wasn't a single SqlDependency.Stop() missing, but more. Imagine 5. Or 10. In this case, depending on your server, you ask yourself why is the server so slow. Unusable slow. In my case, it's a very small server, just for development. Dual core Blade with 1 GB RAM and 60 GB hard disc space, running Windows 2003, SQL Server 2005 SP1, later SP2, and an Oracle 10g (not used but running). Four missing Stop's leads to a new server because noone knows why the server was getting so slow.
 
This happened to me. It doesn't matter why the SqlDependency.Stop() is missing. It can be the developer not reading the manuals carefully Shucks | :-> Or it can be a crashing application.
 
It's not a problem of the solution mentioned in your article. It's a bug not found during development of SQL Server, beta and CTP. For me working with the sa account is no workaround. I must tell our DB administrator tomorrow so he knows where to look if our application goes live in two weeks.
 
Thanks again,
Martin
GeneralRe: Helped a lot, and there's a bug in SQL Server with itmemberMichael Vanhoutte25 Jan '08 - 20:21 
Thanks for your feedback. I was not aware that this could happen when you didn't perform a Stop.
 
What I had already noticed was that not cleaning up properly (which sometimes happen during development when you cancel a console app for example something by pressing Ctrl-C) will leave Service Broker Queues and Services in the database that don't ever get cleaned up. You'll find them under Service Broker|Queues and Service Broker|Services in the Management Studio.
 
Regards,
Michael
GeneralRe: Helped a lot, and there's a bug in SQL Server with itmemberMartin Sp.8 Nov '11 - 9:07 
Finally, I tested it under SQL Server 2008 R2 SP1 again. And it works now, the bug is fixed.
 
Regards,
Martin
GeneralGreat!memberMike Eby15 Jan '08 - 10:53 
I struggled with this for whole day trying find out what was wrong. You answered all my questions and solved my problem. This a great feature of SQL server 2005 and really gives a nice polish to an application.
 
Thanks!
Mike
QuestionIs GRANT VIEW DEFINITION necessary?memberMikael Jirhage2 Oct '06 - 2:01 
Hi,
 
Is GRANT VIEW DEFINITION TO [sql_dependency_starter] really necessary? I have set up SqlCacheDependency, and it's working, but I have not set this grant. I'm just wandering if I will have any problems in the future because of this.
 
Regards,
 
Mikael Jirhage
Sweden
AnswerRe: Is GRANT VIEW DEFINITION necessary?memberMichael Vanhoutte2 Oct '06 - 21:37 
I honestly don't really know. I added this right because it was explicitely mentioned on Sushil Cordia's blog, but I have never tried it without it.
 
Regards,
Michael
GeneralExcelent!!!membermarcondesf25 Sep '06 - 3:39 
Man, your article is Great!!! I had the same problem when creating subscriptions (I didn´t put the ownership of the schema as you mentioned, that´s why I was getting trouble).
 
Tks!!! and good job!
GeneralYepmemberMarc Leger27 Jul '06 - 11:28 
Thanks for the info. Woulda never got this &(*#U&# to work without your example. Thanks.
GeneralRe: YepmemberMember 259468713 Jun '08 - 4:15 
Michael,
 
This is a great example. It's the complete solution, not just random sections of code that you have to piece together to understand. And, it actually works! This is great. I've spend about two days searching for how to get to work until I came across your article. Amazing. Thanks for taking the time to provide this for us.
 
-B
GeneralnicememberThe_Myth22 Mar '06 - 2:42 
thanks
keep the good work Wink | ;) Smile | :)
 
AMH
Software Developer
LIFE'S SHORT. If you don't look around once in a while you might miss it

 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 22 Mar 2006
Article Copyright 2006 by Michael Vanhoutte
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid