diff --git a/.gitmodules b/.gitmodules
index aecfec5a1ce7191e79be46d0e30a3f3efbbd0744..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +0,0 @@
-[submodule "extern/pybind11"]
-	path = extern/pybind11
-	url = https://github.com/pybind/pybind11.git
-	branch = stable
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b7ae62b8bfaaf8928ef294ad46b80d58cc6ee31c..b11163f15c81014edb039d685d27ebb7c96e2f1a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -649,53 +649,16 @@ endif()
 ##
 #############################################################################################################################
 if ( WALBERLA_BUILD_WITH_PYTHON )
-    if(WALBERLA_CXX_COMPILER_IS_INTEL)
-        # Intel C++17 support introduced in 2.6.2 (https://github.com/pybind/pybind11/pull/2729)
-        set(PYBIND11_MINIMUM_VERSION "2.6.2")
-    else()
-        set(PYBIND11_MINIMUM_VERSION "2.6.0")
-    endif()
-
-    execute_process(COMMAND ${Python_EXECUTABLE} -c "import pybind11; print(pybind11._version.__version__)"
-                    OUTPUT_VARIABLE pybind11_VERSION ERROR_QUIET RESULT_VARIABLE pybind11_VERSION_RESULT)
-    string(STRIP "${pybind11_VERSION}" pybind11_VERSION)
-    if(pybind11_VERSION_RESULT EQUAL "0" AND pybind11_VERSION VERSION_GREATER_EQUAL "${PYBIND11_MINIMUM_VERSION}")
-        execute_process(COMMAND ${Python_EXECUTABLE} -m pybind11 --cmakedir
-                        OUTPUT_VARIABLE PYBIND11_CMAKE_PATH)
-        string(STRIP "${PYBIND11_CMAKE_PATH}" PYBIND11_CMAKE_PATH)
-        find_package(pybind11 PATHS "${PYBIND11_CMAKE_PATH}" NO_DEFAULT_PATH REQUIRED)
-    else()
-        find_package(Git QUIET)
-        if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
-           # Update submodules as needed
-           if(WALBERLA_GIT_SUBMODULE_AUTO)
-              message(STATUS "Submodule update")
-              execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
-                    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-                    RESULT_VARIABLE GIT_SUBMOD_RESULT)
-              if(NOT GIT_SUBMOD_RESULT EQUAL "0")
-                 message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
-              endif()
-           endif()
-        endif()
 
-        if(NOT EXISTS "${PROJECT_SOURCE_DIR}/extern/pybind11/CMakeLists.txt")
-            if(EXISTS "${PROJECT_SOURCE_DIR}/.git")
-                message(FATAL_ERROR "Please update git submodules or install pybind11 via pip.")
-            else()
-                message(FATAL_ERROR "Please install pybind11 via pip or download it to ${PROJECT_SOURCE_DIR}/extern/pybind11.")
-            endif()
-        endif()
+    include(FetchContent)
 
-        add_subdirectory(extern/pybind11)
+    FetchContent_Declare(
+            pybind11
+            GIT_REPOSITORY https://github.com/pybind/pybind11.git
+            GIT_TAG        v2.6.2
+    )
 
-        if(pybind11_VERSION VERSION_LESS "2.6.2")
-            # if pybind11 was installed into ${Python_INCLUDE_DIRS} (e.g. by pip), that will have a higher priority than the Git submodule unless we reorder the search path
-            # introduced in 2.6.0 (https://github.com/pybind/pybind11/issues/2709), fixed in 2.6.2 (https://github.com/pybind/pybind11/pull/2716)
-            set_property( TARGET pybind11::pybind11
-                          PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/extern/pybind11/include" "${Python_INCLUDE_DIRS}")
-        endif()
-    endif()
+    FetchContent_MakeAvailable(pybind11)
 
     # a python module is a shared library - so everything has to be compiled to position independent code
     # otherwise linking the static libs into the shared lib will result in errors
diff --git a/extern/pybind11 b/extern/pybind11
deleted file mode 160000
index 58c382a8e3d7081364d2f5c62e7f429f0412743b..0000000000000000000000000000000000000000
--- a/extern/pybind11
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 58c382a8e3d7081364d2f5c62e7f429f0412743b