diff --git a/lib/ovn-parallel-hmap.c b/lib/ovn-parallel-hmap.c
index b8c7ac786..cae0b3110 100644
--- a/lib/ovn-parallel-hmap.c
+++ b/lib/ovn-parallel-hmap.c
@@ -62,7 +62,7 @@ static int pool_size;
 static int sembase;
 
 static void worker_pool_hook(void *aux OVS_UNUSED);
-static void setup_worker_pools(bool force);
+static void setup_worker_pools(bool force, unsigned int thread_num);
 static void merge_list_results(struct worker_pool *pool OVS_UNUSED,
                                void *fin_result, void *result_frags,
                                int index);
@@ -86,14 +86,14 @@ ovn_can_parallelize_hashes(bool force_parallel)
             &test,
             true)) {
         ovs_mutex_lock(&init_mutex);
-        setup_worker_pools(force_parallel);
+        setup_worker_pools(force_parallel, 0);
         ovs_mutex_unlock(&init_mutex);
     }
     return can_parallelize;
 }
 
 struct worker_pool *
-ovn_add_worker_pool(void *(*start)(void *))
+ovn_add_worker_pool(void *(*start)(void *), unsigned int thread_num)
 {
     struct worker_pool *new_pool = NULL;
     struct worker_control *new_control;
@@ -109,7 +109,7 @@ ovn_add_worker_pool(void *(*start)(void *))
             &test,
             true)) {
         ovs_mutex_lock(&init_mutex);
-        setup_worker_pools(false);
+        setup_worker_pools(false, thread_num);
         ovs_mutex_unlock(&init_mutex);
     }
 
@@ -401,14 +401,14 @@ worker_pool_hook(void *aux OVS_UNUSED) {
 }
 
 static void
-setup_worker_pools(bool force) {
+setup_worker_pools(bool force, unsigned int thread_num) {
     int cores, nodes;
 
     nodes = ovs_numa_get_n_numas();
     if (nodes == OVS_NUMA_UNSPEC || nodes <= 0) {
         nodes = 1;
     }
-    cores = ovs_numa_get_n_cores();
+    cores = thread_num ? thread_num : ovs_numa_get_n_cores();
 
     /* If there is no NUMA config, use 4 cores.
      * If there is NUMA config use half the cores on
diff --git a/lib/ovn-parallel-hmap.h b/lib/ovn-parallel-hmap.h
index 0af8914c4..9637a273d 100644
--- a/lib/ovn-parallel-hmap.h
+++ b/lib/ovn-parallel-hmap.h
@@ -95,7 +95,8 @@ struct worker_pool {
 /* Add a worker pool for thread function start() which expects a pointer to
  * a worker_control structure as an argument. */
 
-struct worker_pool *ovn_add_worker_pool(void *(*start)(void *));
+struct worker_pool *ovn_add_worker_pool(void *(*start)(void *),
+                                        unsigned int thread_num);
 
 /* Setting this to true will make all processing threads exit */
 
@@ -265,7 +266,7 @@ bool ovn_can_parallelize_hashes(bool force_parallel);
 
 #define stop_parallel_processing() ovn_stop_parallel_processing()
 
-#define add_worker_pool(start) ovn_add_worker_pool(start)
+#define add_worker_pool(start, thread_num) ovn_add_worker_pool(start, thread_num)
 
 #define fast_hmap_size_for(hmap, size) ovn_fast_hmap_size_for(hmap, size)
 
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 570c6a3ef..ffefac361 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -4153,6 +4153,7 @@ ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od,
  * logical datapath only by creating a datapath group. */
 static bool use_logical_dp_groups = false;
 static bool use_parallel_build = true;
+static unsigned int num_parallel_threads;
 
 static struct hashrow_locks lflow_locks;
 
@@ -12219,7 +12220,8 @@ init_lflows_thread_pool(void)
     int index;
 
     if (!pool_init_done) {
-        struct worker_pool *pool = add_worker_pool(build_lflows_thread);
+        struct worker_pool *pool = add_worker_pool(build_lflows_thread,
+                                                   num_parallel_threads);
         pool_init_done = true;
         if (pool) {
             build_lflows_pool = xmalloc(sizeof(*build_lflows_pool));
@@ -13456,6 +13458,9 @@ ovnnb_db_run(struct northd_context *ctx,
         (smap_get_bool(&nb->options, "use_parallel_build", false) &&
          ovn_can_parallelize_hashes(false));
 
+    num_parallel_threads =
+        smap_get_uint(&nb->options, "num_parallel_threads", 0);
+
     use_logical_dp_groups = smap_get_bool(&nb->options,
                                           "use_logical_dp_groups", false);
     use_ct_inv_match = smap_get_bool(&nb->options,
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 36a77097c..d5bfb7ece 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -226,6 +226,16 @@
           The default value is <code>false</code>.
         </p>
       </column>
+      <column name="options" key="num_parallel_threads">
+        <p>
+          Manually specify the number of threads to be used for parallel
+          logical flow computation.
+        </p>
+        <p>
+          The number of threads utilized will be determined by the number
+          of vCPUs on the system if this value is not specified.
+        </p>
+      </column>
 
       <column name="options" key="ignore_lsp_down">
         <p>
