diff --git a/.github/workflows/macOS.yaml b/.github/workflows/macOS.yaml
index 73c37e3861ef3c5eb2b0570d63f7760d1d23af49..a5ab6fc383848fee67cbe78ea500ce074604ccdc 100644
--- a/.github/workflows/macOS.yaml
+++ b/.github/workflows/macOS.yaml
@@ -19,7 +19,7 @@ jobs:
 
       - name: Install libknot from sources
         env:
-          KNOT_DNS_VERSION: '3.0'
+          KNOT_DNS_VERSION: '3.1'
         run: |
           git clone -b ${KNOT_DNS_VERSION} https://gitlab.nic.cz/knot/knot-dns.git
           cd knot-dns
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 6a668a47795c72cc2674b64e1fa694ede6693784..72abdc4013bc08cb9d29dd75f1d4aa59c153c08f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -10,7 +10,7 @@ variables:
   RESPDIFF_COUNT: 1
   RESPDIFF_FORCE: 0
   RESPERF_FORCE: 0
-  KNOT_VERSION: '3.0'
+  KNOT_VERSION: '3.1'
   LIBKRES_ABI: 9
   LIBKRES_NAME: libkres
   MESON_TEST: meson test -C build_ci* -t 4 --print-errorlogs
@@ -261,11 +261,12 @@ lint:tidy:
     - ninja -C build_ci_lib daemon/kresd
     - ninja -C build_ci_lib kres-gen
     - git diff --quiet || (git diff; exit 1)
-kres-gen-default:
+kres-gen-30:
   <<: *kres-gen
-kres-gen-master:
+  image: $CI_REGISTRY/knot/knot-resolver/ci/debian-11:knot-3.0
+kres-gen-31:
   <<: *kres-gen
-  image: $CI_REGISTRY/knot/knot-resolver/ci/debian-11:knot-master
+  image: $CI_REGISTRY/knot/knot-resolver/ci/debian-11:knot-3.1
 
 root.hints:
   <<: *sanity
diff --git a/ci/debian-11/Dockerfile b/ci/debian-11/Dockerfile
index 5f2a51131a022b02530d2e9952bf6d92d9d395de..672beb266a928ade4958ad85deda7c28d1ebe71a 100644
--- a/ci/debian-11/Dockerfile
+++ b/ci/debian-11/Dockerfile
@@ -3,7 +3,7 @@
 FROM debian:bullseye
 MAINTAINER Knot Resolver <knot-resolver@labs.nic.cz>
 # >= 3.0 needed because of --enable-xdp=yes
-ARG KNOT_BRANCH=3.0
+ARG KNOT_BRANCH=3.1
 ENV DEBIAN_FRONTEND=noninteractive
 
 WORKDIR /root
diff --git a/tests/pytests/kresd.py b/tests/pytests/kresd.py
index 7eeceb68a9e09add7473474ca8d0a5a282cacc86..e0c216ac924ece37dbe1f757eb69be64444e7662 100644
--- a/tests/pytests/kresd.py
+++ b/tests/pytests/kresd.py
@@ -40,7 +40,7 @@ def create_file_from_template(template_path, dest, data):
     template = env.get_template(template_path)
     rendered_template = template.render(**data)
 
-    with open(dest, "w") as fh:
+    with open(dest, "w", encoding='UTF-8') as fh:
         fh.write(rendered_template)
 
 
@@ -92,7 +92,7 @@ class Kresd(ContextDecorator):
             self.tls_port = make_port(self.ip, self.ip6)
 
         create_file_from_template(KRESD_CONF_TEMPLATE, self.config_path, {'kresd': self})
-        self.logfile = open(self.logfile_path, 'w')
+        self.logfile = open(self.logfile_path, 'w', encoding='UTF-8')
         self.process = subprocess.Popen(
             ['kresd', '-c', self.config_path, '-n', self.workdir],
             stderr=self.logfile, env=os.environ.copy())
@@ -112,7 +112,7 @@ class Kresd(ContextDecorator):
                 raise RuntimeError("Kresd crashed with returncode: {}".format(
                     self.process.returncode))
         except (RuntimeError, ConnectionError):  # pylint: disable=try-except-raise
-            with open(self.logfile_path) as log:  # print log for debugging
+            with open(self.logfile_path, encoding='UTF-8') as log:  # print log for debugging
                 print(log.read())
             raise
 
@@ -221,7 +221,7 @@ class Kresd(ContextDecorator):
 
     def partial_log(self):
         partial_log = '\n (... ommiting log start)\n'
-        with open(self.logfile_path) as log:  # display partial log for debugging
+        with open(self.logfile_path, encoding='UTF-8') as log:  # display partial log for debugging
             past_startup_msgid = False
             past_startup = False
             for line in log:
diff --git a/tests/pytests/proxy.py b/tests/pytests/proxy.py
index a55542bb457c0f56c1d7d98a6c9bb36da4b2c63f..b8a53cd8051f1c1192cce9d5d14bd0ab07c57f5f 100644
--- a/tests/pytests/proxy.py
+++ b/tests/pytests/proxy.py
@@ -135,9 +135,9 @@ def kresd_tls_client(
     assert proxy.upstream_ip in ALLOWED_IPS, "only localhost IPs are supported for proxy"
 
     if kresd_tls_client_kwargs is None:
-        kresd_tls_client_kwargs = dict()
+        kresd_tls_client_kwargs = {}
     if kresd_fwd_target_kwargs is None:
-        kresd_fwd_target_kwargs = dict()
+        kresd_fwd_target_kwargs = {}
 
     # run forward target instance
     dir1 = os.path.join(workdir, 'kresd_fwd_target')
diff --git a/tests/pytests/pylintrc b/tests/pytests/pylintrc
index a667afb023e806b1305d1e5539f703a419a4ebb9..2c406be20d7b2b8ae0504abc9f7213f48175fa78 100644
--- a/tests/pytests/pylintrc
+++ b/tests/pytests/pylintrc
@@ -16,6 +16,7 @@ disable=
     no-else-return,
     redefined-outer-name,  # commonly used with pytest fixtures
     consider-using-with,
+    consider-using-f-string,
 
 
 [SIMILARITIES]