diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 7fa06bf672ea380ef352cbd80e5cce45e11beaeb..18af1099f1b33999550ef28de65110470bc5cd5b 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -47,7 +47,6 @@ namespace Grpc.Core
     public class GrpcEnvironment
     {
         const int MinDefaultThreadPoolSize = 4;
-        const int DefaultCompletionQueueCount = 1;
 
         static object staticLock = new object();
         static GrpcEnvironment instance;
@@ -166,9 +165,7 @@ namespace Grpc.Core
         private GrpcEnvironment()
         {
             GrpcNativeInit();
-
-            var cqCount = customCompletionQueueCount ?? DefaultCompletionQueueCount;
-            threadPool = new GrpcThreadPool(this, GetThreadPoolSizeOrDefault(), cqCount);
+            threadPool = new GrpcThreadPool(this, GetThreadPoolSizeOrDefault(), GetCompletionQueueCountOrDefault());
             threadPool.Start();
         }
 
@@ -250,5 +247,15 @@ namespace Grpc.Core
             // more work, but seems to work reasonably well for a start.
             return Math.Max(MinDefaultThreadPoolSize, Environment.ProcessorCount / 2);
         }
+
+        private int GetCompletionQueueCountOrDefault()
+        {
+            if (customCompletionQueueCount.HasValue)
+            {
+                return customCompletionQueueCount.Value;
+            }
+            // by default, create a completion queue for each thread
+            return GetThreadPoolSizeOrDefault();
+        }
     }
 }