I recently needed to change the Transaction Isolation Level of one of our databases in an Availability Group. As it turns out, this is not as straight forward as you might think. Normally all you would have to do is run an ALTER DATABASE statement, but having the database in an Availability Group adds another layer of complexity.
For starters, just trying to run the ALTER DATABASE statement against the database on your primary Availability Group server will result in the following error:
Msg 5070, Level 16, State 2
Database state cannot be changed while other users are using the database ‘TestDB’
Msg 5069, Level 16, State 1
ALTER DATABASE statement failed.
Ok, so users are connected to our database. We just need to put it in single user mode to make our change, right? WRONG! Trying to run SET SINGLE_USER results in the following error:
Msg 1468, Level 16, State 1
The operation cannot be performed on database “TestDB” because it is involved in a database mirroring session or an availability group. Some operations are not allowed on a database that is participating in a database mirroring session or in an availability group.
Msg 5069, Level 16, State 1
ALTER DATABASE statement failed.
Well, isn’t that lovely. Some operations are not allowed on a database that is participating in an availability group. Great.
So, how do we change the Transaction Isolation Level? After a little trial and error (and a lot of Googling), I was able to make the change using the following solution.
- Drop the database from the Availability Group – Yep, that’s right, you have to completely remove the database from the Availability Group, which means that this database will not be available on your Primary or Secondary servers, and will be unavailable to your applications. (So, you’ll have to schedule some down time to do this)
1 2 3 |
ALTER AVAILABILITY GROUP [TestAG] REMOVE DATABASE [TestDB]; |
- Put the database in Single User Mode – This isn’t always required, though it may be, depending on what Transaction Isolation Level you are wanting to set. In may case, I was enabling the READ_COMMITTED_SNAPSHOT option, and in order to do that only the connection executing the ALTER DATABASE command is allowed in the database. Plus, even though the database isn’t in the Availability group at the moment, users can still still connect directly to it on the server instead of accessing it via the Availability Group Listener.
1 2 3 |
ALTER DATABASE [TestDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; |
- Modify the Transaction Isolation Level – This is my code for enabling Read Committed Snapshot Isolation, be sure to change it to whatever Isolation Level you need.
1 2 3 4 |
ALTER DATABASE [TestDB] SET READ_COMMITTED_SNAPSHOT ON; ALTER DATABASE [TestDB] SET ALLOW_SNAPSHOT_ISOLATION ON; |
- Turn Multi User back on
1 2 3 |
ALTER DATABASE [TestDB] SET MULTI_USER; |
- Add the database back to the Availability Group
1 2 3 |
ALTER AVAILABILITY GROUP [TestAG] ADD DATABASE [TestDB]; |
So, at this point, your database should be back in the Availability Group, and everything on your Primary server should look good.
But wait! We’re not done! None of the copies of our database on our Secondary servers are happy. We need to let them know that our Primary is back online and that they can start synchronizing again. This is actually very easy to do, simply run this ALTER statement on every one of your Secondaries that need to sync back up with the Primary.
- Reconnect the Secondary database to the Availability Group so it starts syncing again
1 2 3 |
ALTER DATABASE [TestDB] SET HADR AVAILABILITY GROUP = [TestAG]; |
Once that is complete, you should be done! It may seem like a lot of work at first, but in reality most of those statements should execute pretty quickly.
Now, there’s one thing I want to point out to save you some trouble. Be sure to disable any transaction log backup jobs for this database while it is out of the Availability Group. If you don’t, you may be doing some database restores. Trust me, I know. It happened to me. A transaction log backup occurred on my database on my Secondary server while I had it out of the Availability Group. This resulted in my Secondary refusing to sync back up with my Primary when I tried to add it back to the Availability Group, because the LSNs were not matching. To fix this, I had to take a FULL backup of my Primary database, and a LOG backup, then restore them both over my Secondary database using the WITH NORECOVERY option. This allowed the database to then sync with my Primary.
Once your Secondaries are re-synced, then you can start your transaction log backup job again, and you should be finished.
Thank you so much for writing this article! I have been struggling with deadlocks in a very bad way. We Created a HA group with SQL Always on and moved all reports to the second node. This helped but did not solve the problem. I found about the RCIS mode and decided to try it and got stuck in the middle of the procedure when I got the error MSG 1468, LEVEL at 4:am with the maintenance window closing fast. I found this article and it got me through what to do and now all of my deadlocks are gone! Thanks again!
Great to hear! I’m glad I could help Ryan. 🙂
Thank Eric, it’s helped me during a new project! Thank a lot.
Awesome! Thanks for letting me know!
Now it seems that in SQL Server 2019 this can be done also without removing the database from the availability group.
For my case I just stopped couple of applications that were doing the majority of the transactions and did run
ALTER DATABASE [YOUR]DB SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE
GO
It did accept it. I tested first in stage environment and then in production. Both worked fine
Thanks! That’s really good to know.