diff --git a/numba/np/ufunc/parallel.py b/numba/np/ufunc/parallel.py
index 1b4a3b53d..33eb623d7 100644
--- a/numba/np/ufunc/parallel.py
+++ b/numba/np/ufunc/parallel.py
@@ -345,7 +345,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)
@@ -358,8 +358,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 83389223d..161de2f08 100644
--- a/numba/np/ufunc/tbbpool.cpp
+++ b/numba/np/ufunc/tbbpool.cpp
@@ -31,12 +31,23 @@ 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)
+
 #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;
+static bool tsh_init = false;
+#endif
 
 #ifdef _MSC_VER
 #define THREAD_LOCAL(ty) __declspec(thread) ty
@@ -75,7 +86,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
@@ -213,12 +228,19 @@ static bool is_main_thread()
     return std::this_thread::get_id() == init_thread_id;
 }
 
+#if HAS_TASK_SCHEDULER_INIT
 static 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");
 }
 
 static void ignore_assertion( const char*, int, const char*, const char * ) {}
+#endif
+
+static bool need_terminate()
+{
+    return tg != nullptr;
+}
 
 static void prepare_fork(void)
 {
@@ -226,14 +248,23 @@ static void prepare_fork(void)
     {
         puts("Suspending TBB: prepare fork");
     }
-    if(tsi)
+    if(need_terminate())
     {
         if(is_main_thread())
         {
             // TBB thread termination must always be called from same thread that called initialize
+#if HAS_TASK_SCHEDULER_INIT
             assertion_handler_type orig = tbb::set_assertion_handler(ignore_blocking_terminate_assertion);
             tsi->blocking_terminate(std::nothrow);
             tbb::set_assertion_handler(orig);
+#endif
+#if HAS_TASK_SCHEDULER_HANDLE
+            if (!tbb::finalize(tsh, std::nothrow))
+            {
+                fprintf(stderr, "Unable to join threads to shut down before fork(). "
+                                "It can break multithreading in child process\n");
+            }
+#endif
             need_reinit_after_fork = true;
         }
         else
@@ -251,9 +282,18 @@ static void reset_after_fork(void)
     {
         puts("Resuming TBB: after fork");
     }
-    if(tsi && need_reinit_after_fork)
+    if (need_reinit_after_fork)
     {
-        tsi->initialize(tsi_count);
+#if HAS_TASK_SCHEDULER_INIT
+        if(tsi)
+        {
+            tsi->initialize(tsi_count);
+        }
+#endif
+#if HAS_TASK_SCHEDULER_HANDLE
+        tsh = tbb::task_scheduler_handle::get();
+	tsh_init = true;
+#endif
         set_main_thread();
         need_reinit_after_fork = false;
     }
@@ -262,7 +302,7 @@ static void reset_after_fork(void)
 #if PY_MAJOR_VERSION >= 3
 static void unload_tbb(void)
 {
-    if(tsi)
+    if (tg)
     {
         if(_DEBUG)
         {
@@ -271,25 +311,45 @@ 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
+    if (tsh_init) {
+        (void)tbb::finalize(tsh, std::nothrow);
+	tsh_init = false;
+    }
+#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_count = count;
     tsi = new tbb::task_scheduler_init(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
 
@@ -311,7 +371,6 @@ static void ready(void)
 {
 }
 
-
 MOD_INIT(tbbpool)
 {
     PyObject *m;
