diff --git a/numba/np/ufunc/parallel.py b/numba/np/ufunc/parallel.py
index b5387c0..5f4d469 100644
--- a/numba/np/ufunc/parallel.py
+++ b/numba/np/ufunc/parallel.py
@@ -337,7 +337,7 @@ def _check_tbb_version_compatible():
         elif _IS_OSX:
             libtbb_name = 'libtbb.dylib'
         elif _IS_LINUX:
-            libtbb_name = 'libtbb.so.2'
+            libtbb_name = 'libtbb.so.12'
         else:
             raise ValueError("Unknown operating system")
         libtbb = CDLL(libtbb_name)
@@ -350,8 +350,8 @@ def _check_tbb_version_compatible():
                    "version 2019.5 or later i.e., "
                    "TBB_INTERFACE_VERSION >= 11005. Found "
                    "TBB_INTERFACE_VERSION = %s. The TBB "
-                   "threading layer is disabled.")
-            problem = errors.NumbaWarning(msg % tbb_iface_ver)
+                   "threading layer is disabled.") % tbb_iface_ver
+            problem = errors.NumbaWarning(msg)
             warnings.warn(problem)
             raise ImportError("Problem with TBB. Reason: %s" % msg)
     except (ValueError, OSError) as e:
diff --git a/numba/np/ufunc/tbbpool.cpp b/numba/np/ufunc/tbbpool.cpp
index faff479..156ad94 100644
--- a/numba/np/ufunc/tbbpool.cpp
+++ b/numba/np/ufunc/tbbpool.cpp
@@ -30,15 +30,27 @@ Implement parallel vectorize workqueue on top of Intel TBB.
 #error "TBB version is too old, 2019 update 5, i.e. TBB_INTERFACE_VERSION >= 11005 required"
 #endif

+#define HAS_TASK_SCHEDULER_INIT (TBB_INTERFACE_VERSION < 12002)
+#define HAS_TASK_SCHEDULER_HANDLE (TBB_INTERFACE_VERSION >= 12003)
+
+#if HAS_TASK_SCHEDULER_INIT
 #define TSI_INIT(count) tbb::task_scheduler_init(count)
 #define TSI_TERMINATE(tsi) tsi->blocking_terminate(std::nothrow)
+#endif

 #define _DEBUG 0
 #define _TRACE_SPLIT 0

 static tbb::task_group *tg = NULL;
+
+#if HAS_TASK_SCHEDULER_INIT
 static tbb::task_scheduler_init *tsi = NULL;
 static int tsi_count = 0;
+#endif
+
+#if HAS_TASK_SCHEDULER_HANDLE
+static tbb::task_scheduler_handle tsh;
+#endif

 #ifdef _MSC_VER
 #define THREAD_LOCAL(ty) __declspec(thread) ty
@@ -77,7 +89,11 @@ get_num_threads(void)
 static int
 get_thread_id(void)
 {
+#if TBB_INTERFACE_VERSION < 12002
     return tbb::task_arena::current_thread_index();
+#else
+    return tbb::this_task_arena::current_thread_index();
+#endif
 }

 // watch the arena, if it decides to create more threads/add threads into the
@@ -202,12 +218,15 @@ parallel_for(void *fn, char **args, size_t *dimensions, size_t *steps, void *dat
     });
 }

+#if HAS_TASK_SCHEDULER_INIT
 void ignore_blocking_terminate_assertion( const char*, int, const char*, const char * )
 {
     tbb::internal::runtime_warning("Unable to wait for threads to shut down before fork(). It can break multithreading in child process\n");
 }

 void ignore_assertion( const char*, int, const char*, const char * ) {}
+#endif
+

 static void prepare_fork(void)
 {
@@ -215,12 +234,20 @@ static void prepare_fork(void)
     {
         puts("Suspending TBB: prepare fork");
     }
+#if HAS_TASK_SCHEDULER_INIT
     if(tsi)
     {
         assertion_handler_type orig = tbb::set_assertion_handler(ignore_blocking_terminate_assertion);
         TSI_TERMINATE(tsi);
         tbb::set_assertion_handler(orig);
     }
+#endif
+#if HAS_TASK_SCHEDULER_HANDLE
+    if (!tbb::finalize(tsh, std::nothrow))
+    {
+        puts("Unable to join threads to shut down before fork(). It can break multithreading in child process\n");
+    }
+#endif
 }

 static void reset_after_fork(void)
@@ -229,14 +256,16 @@ static void reset_after_fork(void)
     {
         puts("Resuming TBB: after fork");
     }
+#if HAS_TASK_SCHEDULER_INIT
     if(tsi)
         tsi->initialize(tsi_count);
+#endif
 }

 #if PY_MAJOR_VERSION >= 3
 static void unload_tbb(void)
 {
-    if(tsi)
+    if (tg)
     {
         if(_DEBUG)
         {
@@ -245,24 +274,41 @@ static void unload_tbb(void)
         tg->wait();
         delete tg;
         tg = NULL;
+    }
+#if HAS_TASK_SCHEDULER_INIT
+    if(tsi)
+    {
         assertion_handler_type orig = tbb::set_assertion_handler(ignore_assertion);
         tsi->terminate(); // no blocking terminate is needed here
         tbb::set_assertion_handler(orig);
         delete tsi;
         tsi = NULL;
     }
+#endif
+#if HAS_TASK_SCHEDULER_HANDLE
+    // bloking terminate is not strictly required here, ignore return value
+    (void)tbb::finalize(tsh, std::nothrow);
+#endif
 }
 #endif

 static void launch_threads(int count)
 {
-    if(tsi)
+    if(tg)
         return;
+
     if(_DEBUG)
         puts("Using TBB");
+
     if(count < 1)
-        count = tbb::task_scheduler_init::automatic;
+        count = tbb::task_arena::automatic;
+#if HAS_TASK_SCHEDULER_INIT
     tsi = new TSI_INIT(tsi_count = count);
+#endif
+
+#if HAS_TASK_SCHEDULER_HANDLE
+    tsh = tbb::task_scheduler_handle::get();
+#endif
     tg = new tbb::task_group;
     tg->run([] {}); // start creating threads asynchronously

@@ -282,7 +328,6 @@ static void ready(void)
 {
 }

-
 MOD_INIT(tbbpool)
 {
     PyObject *m;