diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9586675..840ad2d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,7 +31,7 @@ set(
 enable_testing()
 
 find_package(PkgConfig)
-find_package(Boost COMPONENTS filesystem program_options REQUIRED)
+find_package(Boost 1.66 COMPONENTS filesystem program_options REQUIRED)
 find_package(nlohmann_json 3.11 REQUIRED)
 
 pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED)
diff --git a/src/biometry/qml/Biometryd/plugin.cpp b/src/biometry/qml/Biometryd/plugin.cpp
index 64798ec..f398962 100644
--- a/src/biometry/qml/Biometryd/plugin.cpp
+++ b/src/biometry/qml/Biometryd/plugin.cpp
@@ -77,18 +77,18 @@ public:
 
     void dispatch(const std::function<void()>& f)
     {
-        service.post(f);
+        post( service, bind_executor( service, f ));
     }
 
 private:
     Dispatcher()
-        : keep_alive{service},
+        : keep_alive{service.get_executor()},
           t{[this]() { service.run(); }}
     {
     }
 
-    boost::asio::io_service service;
-    boost::asio::io_service::work keep_alive;
+    boost::asio::io_context service;
+    boost::asio::executor_work_guard<boost::asio::io_context::executor_type> keep_alive;
     std::thread t;
 
 };
diff --git a/src/biometry/runtime.cpp b/src/biometry/runtime.cpp
index fa1b338..da99446 100644
--- a/src/biometry/runtime.cpp
+++ b/src/biometry/runtime.cpp
@@ -28,7 +28,7 @@ namespace
 // TODO(tvoss): Catching all exceptions is risky as they might signal unrecoverable
 // errors. We should enable calling code to decide whether an exception should be considered
 // fatal or not.
-void exception_safe_run(boost::asio::io_service& service)
+void exception_safe_run(boost::asio::io_context& service)
 {
     while (true)
     {
@@ -61,7 +61,7 @@ biometry::Runtime::Runtime(std::uint16_t pool_size)
     : pool_size_{pool_size},
       service_{pool_size_},
       strand_{service_},
-      keep_alive_{service_}
+      keep_alive_{service_.get_executor()}
 {
 }
 
@@ -98,11 +98,11 @@ std::function<void(std::function<void()>)> biometry::Runtime::to_dispatcher_func
     auto sp = shared_from_this();
     return [sp](std::function<void()> task)
     {
-        sp->strand_.post(task);
+        post( sp->strand_.context(), bind_executor( sp->strand_, task ));
     };
 }
 
-boost::asio::io_service& biometry::Runtime::service()
+boost::asio::io_context& biometry::Runtime::service()
 {
     return service_;
 }
diff --git a/src/biometry/runtime.h b/src/biometry/runtime.h
index 3d3ef6c..4ac0a04 100644
--- a/src/biometry/runtime.h
+++ b/src/biometry/runtime.h
@@ -67,7 +67,7 @@ public:
 
     // service returns the underlying boost::asio::io_service that is executed
     // by the Runtime.
-    boost::asio::io_service& service();
+    boost::asio::io_context& service();
 
 private:
     // Runtime constructs a new instance, firing up pool_size
@@ -75,9 +75,9 @@ private:
     Runtime(std::uint16_t pool_size);
 
     std::uint16_t pool_size_;
-    boost::asio::io_service service_;
-    boost::asio::io_service::strand strand_;
-    boost::asio::io_service::work keep_alive_;
+    boost::asio::io_context service_;
+    boost::asio::io_context::strand strand_;
+    boost::asio::executor_work_guard<boost::asio::io_context::executor_type> keep_alive_;
     std::vector<std::thread> workers_;
 };
 }
diff --git a/src/biometry/util/dispatcher.cpp b/src/biometry/util/dispatcher.cpp
index 97d56c0..3b4a50d 100644
--- a/src/biometry/util/dispatcher.cpp
+++ b/src/biometry/util/dispatcher.cpp
@@ -32,12 +32,12 @@ public:
 
     void dispatch(const Task &task) override
     {
-        strand.post(task);
+        post( strand.context(), bind_executor( strand, task ));
     }
 
 private:
     std::shared_ptr<biometry::Runtime> rt;
-    boost::asio::io_service::strand strand;
+    boost::asio::io_context::strand strand;
 };
 }
 
