Drop all databases based on age
Your code is very, very close to working.

It's not explicitly clear from the docs but the examples do show this.

When using EXEC (or EXECUTE) with a stored procedure, you write the object name straight after the statement (example 1 below), however when calling a T-SQL string you must include brackets (example 2 below)

Example 1

EXEC dbo.Procedure


Example 2

EXEC ('SELECT * FROM dbo.SomeTable')


As such, your solution should look like this (Note the replacement of the static date with GETDATE() to satisfy your original condition of dropping based on the age of the database):

--For internal objects, always use NVARCHAR - this is what the engine uses internally in most places
DECLARE @DBName NVARCHAR (64)
DECLARE @SQL NVARCHAR (255)
DECLARE DROPDB CURSOR FOR 
SELECT name FROM sys.databases 
--Use GETDATE() with DATEADD for -60 days to get the threshold for deletion
WHERE create_date  &lt;= DATEADD(DD,-60,GETDATE())
AND name NOT IN ('master','model','msdb','tempdb','distribution','ReportServer','ReportServerTempDB')

OPEN DROPDB
FETCH next FROM DROPDB INTO @DBName
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @SQL = 'DROP DATABASE ' + QUOTENAME(@DBName)
            PRINT @SQL
    EXEC (@SQL)
    FETCH next FROM DROPDB INTO @DBName
END
CLOSE DROPDB
DEALLOCATE DROPDB


As an aside, given that this is such a potentially damaging script, I'd drop the EXEC and simply copy the printed statements into a new query to run them. This would avoid any unforeseen accidents as it gives you an opportunity to audit the script before you run it.