So, follow this basic pattern in VB.NET 2002/2003 (pseudo-code): Dim cn As New Connection("…") cn.Open() Try Dim cm As Command = cn.CreateCommand() Try Dim dr As DataReader = cm.ExecuteReader() Try ' do data reading here Finally dr.Close() ' and/or Dispose() – though Close() and Dispose() both work End Try Finally cm.Dispose() End Try Finally cn.Close() ' and/or Dispose() – though Close() and Dispose() both work End Try And in C# 1.0 and 2.0 (pseudo-code): using(Connection cn = new Connection("…")) { cn.Open() using(Command cm = cn.CreateCommand()) { using(DataReader dr = cm.ExecuteReader()) { // do data reading here } } } And in VB 8 (VB.NET 2005) (pseudo-code): Using cn As New Connection("…") cn.Open() Using cm As Command = cn.CreateCommand() Using dr As DataReader = cm.ExecuteReader() ' do data reading here End Using End Using End Using>I'm not sure this is always the case. With ODBC or OLE DB access, there will be unmanaged code called, but if you are using a .Net Provider, I think it's all managed code.