96

When I try to drop a database I get the error "Cannot drop database "dbname" because it is currently in use". However, when I run sp_who2, there are definitely no sessions connected to this database. I've also set the database to single_user mode with rollback immediate.

Why is this happening?

Nick Chammas
  • 14,810
  • 17
  • 76
  • 124
tuseau
  • 1,895
  • 5
  • 18
  • 18

6 Answers6

106

A session connected to another database might have an open transaction that also affects your database - sp_who2 will only show one database. It could also be something as simple as Object Explorer or Object Explorer Details open in SSMS, which again would only show one database in sp_who2.

Don't bother trying to find the session that is responsible; just kill them all with one statement (and make sure it isn't your copy of SSMS that is connected, e.g. another query window, Object Explorer, etc.):

USE master;
GO
ALTER DATABASE dbname SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

Now you will be able to drop it, and do that using DDL, not the UI:

DROP DATABASE dbname;
Aaron Bertrand
  • 181,950
  • 28
  • 405
  • 624
29

Make sure you don't have dependencies like database snapshots on the db you want to remove. Though, the error message would look otherwise. Are you sure that there is no hidden process that is connecting to your database? A good approach would be to run a script which kills all sessions and immediately after rename the database to another name and then drop database.

create a cursor based on this select:

  select  d.name , convert (smallint, req_spid) As spid
      from master.dbo.syslockinfo l, 
           master.dbo.spt_values v,
           master.dbo.spt_values x, 
           master.dbo.spt_values u, 
           master.dbo.sysdatabases d
      where   l.rsc_type = v.number 
      and v.type = 'LR' 
      and l.req_status = x.number 
      and x.type = 'LS' 
      and l.req_mode + 1 = u.number
      and u.type = 'L' 
      and l.rsc_dbid = d.dbid 
      and rsc_dbid = (select top 1 dbid from 
                      master..sysdatabases 
                      where name like 'my_db')

issue inside cursor:

SET @kill_process =  'KILL ' + @spid      
            EXEC master.dbo.sp_executesql @kill_process
                   PRINT 'killed spid : '+ @spid

after the cursor is closed and deallocated:

sp_dboption 'my_db', 'single user', 'TRUE'

go

sp_renamedb 'my_db', 'my_db_old'

go

DROP DATABASE MY_DB_OLD 
Michael Green
  • 25,255
  • 13
  • 54
  • 100
yrushka
  • 1,994
  • 1
  • 16
  • 22
21

How about just seeing what SSMS does when you use the UI but tell it to issue a script for the action? Here is what SSMS does when you right click the DB and choose Delete, then check the box to close existing connections:

EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'yourdbname'
GO

USE [master]
GO
ALTER DATABASE [yourdbname] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE
GO

USE [master]
GO

DROP DATABASE [yourdbname]
GO
Thiago Silva
  • 311
  • 2
  • 4
19

What's your current database when you issue the DROP command? Try this:

use master
go
drop database mydb
go

Also be sure that you are connected as sa and not dbo on whichever database you want to drop.

Gaius
  • 11,238
  • 3
  • 32
  • 64
5

I have faced this situation many times and below is what I do :

When obvious methods do not work .....(just like in your situation) :

Find out the database ID from sysdatabases.

Then execute - sp_lock that will show all the locks on the instance along with spid and dbid.

Kill the spids with the dbid that you are trying to offline or drop.

Though, the process is a bit manual, it can be automated as below :

IF OBJECT_ID('tempdb.dbo.#temp', 'U') IS NOT NULL
  DROP TABLE #temp;
create table #temp (spid int
                , dbid int
                ,ObjId bigint
                , IndId bigint
                ,Type varchar(5)
                ,resource varchar(max)
                ,Mode varchar(5)
                ,status varchar(10));
declare @dbid int
select @dbid =DB_ID(db_name())

insert into #temp
exec sp_lock

select * from #temp
where dbid = @dbid
Kin Shah
  • 62,545
  • 6
  • 124
  • 245
4

Found really simple answer on StackOverflow that worked first time for me:

Here's the SQL from that answer:

DECLARE @DatabaseName nvarchar(50)
SET @DatabaseName = N'YOUR_DABASE_NAME'

DECLARE @SQL varchar(max)

SELECT @SQL = COALESCE(@SQL,'') + 'Kill ' + Convert(varchar, SPId) + ';' FROM MASTER..SysProcesses WHERE DBId = DB_ID(@DatabaseName) AND SPId <> @@SPId

--Use this to see results SELECT @SQL --Uncomment this to run it --EXEC(@SQL)

Marcello Miorelli
  • 17,274
  • 53
  • 180
  • 320
Adrian Carr
  • 149
  • 3