“Timeout expired” errors may be result of a wide range of issues such as network delays, application hangs, database locks. I have recently worked on an issue that was the result of ADO.NET database pool exhaustion.
The entire error message we captured in the DebugDiag dump file:
Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
Root cause of ADO.NET database pool exhaustion
Looking at the dump file analysis above, I saw that the MaxPoolSize was reached for ADO.NET connections. This points out a coding issue.
From the application code, I noticed that a
SqlDataReader object is created but never closed in the authentication function. I also didn’t see that connection is closed. It means the application is creating a new connection each time this function is called (probably in every page). Therefore, the connection pool is adding up quickly. The default
MaxPoolSize is 100. When this limit is reached, new requests are queued until the time-out occurs which is 15 seconds by default.
This is the reason a user is waiting for the page to load for a while. Since there is still no availability in the connection pool after waiting for 15 seconds, the request is timing out and the page is redirected to the custom error page.
It explains why this issue happens intermittently. If you spend time in the application for a long time until exhausting the connection pool, you will come across this issue with every user account.
In addition to the connection pool issue, if you see assembly related database connection issue, check this post out: Solved: “Could not load file or assembly ‘Microsoft.SqlServer.Management.Sdk. The system cannot find the file specified”
Solution for “The timeout period elapsed prior to obtaining a connection from the pool”
As a temporary solution, you can recycle the application pool. It clears the connection pool.
In order to fix this issue permanently, the ADO.NET connection function should be edited. The connection and
dataReader objects should be closed after each transaction as mentioned in this article:
We strongly recommend that you always close the connection when you are finished using it so that the connection will be returned to the pool. You can do this using either the
Disposemethods of the
Connectionobject, or by opening all connections inside a
usingstatement in C#, or a
Usingstatement in Visual Basic. Connections that are not explicitly closed might not be added or returned to the pool. For more information, see using Statement or How to: Dispose of a System Resource for Visual Basic.
If you are seing this issue while working with AD RMS, check this post out for a solution: How to clear AD RMS super user group membership cache