diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 51c4486b50ed0bd260a0b62aa01fbd3eca608769..8b15e764abae0844f7d39fc7b9a5098edbc47c3c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -72,8 +72,9 @@ trigger_build:
     # Renaming variables.
     F_BRANCH: $CI_COMMIT_REF_NAME
     PYLIB: $CI_COMMIT_REF_NAME
-    TriggeredBy: PYLIB
-    TriggeredByHash: $CI_COMMIT_SHORT_SHA
+    TRIGGERED_BY_REPO: PYLIB
+    TRIGGERED_BY_REF: $CI_COMMIT_REF_NAME
+    TRIGGERED_BY_HASH: $CI_COMMIT_SHORT_SHA
 
   trigger:
     project: caosdb/src/caosdb-deploy
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9e15263b014e05f3acfc225b922db54d8df776e2..2bca92172175f89d8cea58addb8e9304e26f3286 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,8 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
-## [Unreleased]
+## [0.8.0] - 2022-07-12
+(Timm Fitschen)
 
 ### Added ###
 
@@ -27,6 +28,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * Support for Python 3.6 and Python 3.7
 
 ### Fixed ###
+* [#75](https://gitlab.indiscale.com/caosdb/src/caosdb-pylib/-/issues/75), [#103](https://gitlab.indiscale.com/caosdb/src/caosdb-pylib/-/issues/103) Fixed JSON schema to allow more sections, and correct requirements for
+  password method.
+- `read()` of MockupResponse returns now an appropriate type on modern systems
+
+* [caosdb-server#142](https://gitlab.com/caosdb/caosdb-server/-/issues/142)
+  Can't create users with dots in their user names
 
 ### Security ###
 
diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md
index 117e764e44e7fa2693919451b653647b370be63f..cccdbcba9df2cc63e08a93c8b99dc13c92211f7f 100644
--- a/DEPENDENCIES.md
+++ b/DEPENDENCIES.md
@@ -1,4 +1,4 @@
-* caosdb-server >= 0.7.2
+* caosdb-server >= 0.8.0
 * Python >= 3.8
 * pip >= 20.0.2
 
diff --git a/README.md b/README.md
index 04b34cbc07c98e73740b13200ed83fe067af99d2..602df33cecfc8ec37fd791e3257221e66f120cb3 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ However, you can also create an issue for it.
 
 * Copyright (C) 2018 Research Group Biomedical Physics, Max Planck Institute
   for Dynamics and Self-Organization Göttingen.
-* Copyright (C) 2020-2021 Indiscale GmbH <info@indiscale.com>
+* Copyright (C) 2020-2022 Indiscale GmbH <info@indiscale.com>
 
 All files in this repository are licensed under a [GNU Affero General Public
 License](LICENCE.md) (version 3 or later).
diff --git a/RELEASE_GUIDELINES.md b/RELEASE_GUIDELINES.md
index b4e38d643756798f0ba8b07d6eceec529cbb3054..00d0362e6630267c135e2566b993a91fccf1fd91 100644
--- a/RELEASE_GUIDELINES.md
+++ b/RELEASE_GUIDELINES.md
@@ -42,4 +42,6 @@ guidelines of the CaosDB Project
 
 12. After the merge of main to dev, start a new development version by
     setting `ISRELEASED` to `False` and by increasing at least the `MICRO`
-    version in [setup.py](./setup.py) and preparing CHANGELOG.md.
+    version in [setup.py](./setup.py).
+    Also update CHANGELOG.md (new "Unreleased" section).
+    Also update `src/doc/conf.py`.
diff --git a/setup.py b/setup.py
index 70d87707b71e79ac7a819a15d9df4ae1d9327b2d..9f392889c314bb54b0557f53793a034f6d5161b5 100755
--- a/setup.py
+++ b/setup.py
@@ -47,13 +47,13 @@ from setuptools import find_packages, setup
 
 ISRELEASED = False
 MAJOR = 0
-MINOR = 7
-MICRO = 5
+MINOR = 9
+MICRO = 0
 # Do not tag as pre-release until this commit
 # https://github.com/pypa/packaging/pull/515
 # has made it into a release. Probably we should wait for pypa/packaging>=21.4
 # https://github.com/pypa/packaging/releases
-PRE = "" # "dev"  # e.g. rc0, alpha.1, 0.beta-23
+PRE = "dev" # "dev"  # e.g. rc0, alpha.1, 0.beta-23
 
 if PRE:
     VERSION = "{}.{}.{}-{}".format(MAJOR, MINOR, MICRO, PRE)
diff --git a/src/caosdb/common/administration.py b/src/caosdb/common/administration.py
index cef0bd1cf6fceb9d8ec89324ba9ca540b79889cb..98d4d2826da7131ef79b5c3cc9b3d9597abc0248 100644
--- a/src/caosdb/common/administration.py
+++ b/src/caosdb/common/administration.py
@@ -196,17 +196,9 @@ def _update_user(name, realm=None, password=None, status=None,
         e.msg = "You are not permitted to update this user."
         raise e
     except HTTPClientError as e:
-        if e.status == 409:
-            e.msg = "Entity does not exist."
-
-        if e.status == 422:
-            e.msg = """Maybe the password does not match the required standard?
-                        The current requirements are:
-                        - at least 8 characters
-                        - at least 1 number
-                        - at least 1 lower case character
-                        - at least 1 upper case character
-                        - at least 1 special character"""
+        for elem in etree.fromstring(e.body):
+            if elem.tag == "Error":
+                e.msg = elem.get("description")
         raise
 
 
@@ -231,17 +223,9 @@ def _insert_user(name, password=None, status=None, email=None, entity=None, **kw
         e.msg = "You are not permitted to insert a new user."
         raise e
     except HTTPClientError as e:
-        if e.status == 409:
-            e.msg = "User name is already in use."
-
-        if e.status == 422:
-            e.msg = """Maybe the password does not match the required standard?
-                        The current requirements are:
-                        - at least 8 characters
-                        - at least 1 number
-                        - at least 1 lower case character
-                        - at least 1 upper case character
-                        - at least 1 special character"""
+        for elem in etree.fromstring(e.body):
+            if elem.tag == "Error":
+                e.msg = elem.get("description")
         raise e
 
 
diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py
index ee7a69e092b8047a1705a2deb31eb0df8f445991..a50411253fa2c83438e0b91e51c6e004a143acd3 100644
--- a/src/caosdb/common/models.py
+++ b/src/caosdb/common/models.py
@@ -44,7 +44,6 @@ from hashlib import sha512
 from os import listdir
 from os.path import isdir
 from random import randint
-from sys import hexversion
 from tempfile import NamedTemporaryFile
 from warnings import warn
 from lxml import etree
@@ -1405,11 +1404,7 @@ def _log_request(request, xml_body=None):
 def _log_response(body):
     if Container._debug() > 0:
         print("\n======== Response body ========\n")
-
-        if hexversion < 0x03000000:
-            print(body)
-        else:
-            print(body.decode())
+        print(body.decode())
         print("\n===============================\n")
 
 
diff --git a/src/caosdb/connection/__init__.py b/src/caosdb/connection/__init__.py
index 638d4f0a8400f0ea1a2f197dcfdbe3fc933d4c10..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/src/caosdb/connection/__init__.py
+++ b/src/caosdb/connection/__init__.py
@@ -1,29 +0,0 @@
-# -*- encoding: utf-8 -*-
-#
-# ** header v3.0
-# This file is a part of the CaosDB Project.
-#
-# Copyright (C) 2018 Research Group Biomedical Physics,
-# Max-Planck-Institute for Dynamics and Self-Organization Göttingen
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-# ** end header
-#
-from sys import hexversion
-from .utils import check_python_ssl_version
-
-check_python_ssl_version(hexversion)
-del check_python_ssl_version
-del hexversion
diff --git a/src/caosdb/connection/encode.py b/src/caosdb/connection/encode.py
index 970c4191e1defc55b2b4a6c7d01e0c9d4ba2952f..7b092aae784a76abec0104ef7269df7ae0111b3b 100644
--- a/src/caosdb/connection/encode.py
+++ b/src/caosdb/connection/encode.py
@@ -53,19 +53,9 @@ __all__ = [
     'gen_boundary', 'encode_and_quote', 'MultipartParam', 'encode_string',
     'encode_file_header', 'get_body_size', 'get_headers', 'multipart_encode'
 ]
-from sys import hexversion
-try:
-    from urllib.parse import quote_plus
-except ImportError:
-    from urllib import quote_plus
-
-try:
-    from io import UnsupportedOperation
-except ImportError:
-    UnsupportedOperation = None
-
+from urllib.parse import quote_plus
+from io import UnsupportedOperation
 import uuid
-
 import re
 import os
 import mimetypes
@@ -83,24 +73,9 @@ def encode_and_quote(data):
     if data is None:
         return None
 
-    if hexversion < 0x03000000:
-        if isinstance(data, unicode):
-            data = data.encode("utf-8")
     return quote_plus(data)
 
 
-def _strify(string):
-    """If string is a unicode string, encode it to UTF-8 and return the
-    results, otherwise return str(s), or None if s is None."""
-    if string is None:
-        return None
-    if hexversion < 0x03000000:
-        if isinstance(string, unicode):
-            return string.encode("utf-8")
-        return str(string)
-    return str(string)
-
-
 class MultipartParam(object):
     """Represents a single parameter in a multipart/form-data request.
 
@@ -143,22 +118,14 @@ class MultipartParam(object):
                  fileobj=None,
                  callback=None):
         self.name = Header(name).encode()
-        self.value = _strify(value)
+        self.value = value
         if filename is None:
             self.filename = None
-        elif hexversion < 0x03000000:
-            if isinstance(filename, unicode):
-                # Encode with XML entities
-                self.filename = filename.encode("ascii", "xmlcharrefreplace")
-            else:
-                self.filename = str(filename)
-            self.filename = self.filename.encode("string_escape").\
-                replace('"', '\\"')
         else:
             bfilename = filename.encode("ascii", "xmlcharrefreplace")
             self.filename = bfilename.decode("UTF-8").replace('"', '\\"')
 
-        self.filetype = _strify(filetype)
+        self.filetype = filetype
 
         self.filesize = filesize
         self.fileobj = fileobj
diff --git a/src/caosdb/connection/mockup.py b/src/caosdb/connection/mockup.py
index 692ec2b13f16556a9acfab2a377a04aaf27d650c..b37670b867cd88cf47e64084c6ccc802cad463b4 100644
--- a/src/caosdb/connection/mockup.py
+++ b/src/caosdb/connection/mockup.py
@@ -56,7 +56,7 @@ class MockUpResponse(CaosDBHTTPResponse):
 
     def read(self, size=-1):
         """Return the body of the response."""
-        return self.response.read(size)
+        return self.response.read(size).encode()
 
     def getheader(self, name, default=None):
         """Get the contents of the header `name`, or `default` if there is no
diff --git a/src/caosdb/connection/utils.py b/src/caosdb/connection/utils.py
index 8c1518c1ba66b45c69d5b9fa0d137f0df633cd0c..9056bf9dea14fa2fa441fa13a5efe8e776990284 100644
--- a/src/caosdb/connection/utils.py
+++ b/src/caosdb/connection/utils.py
@@ -23,19 +23,9 @@
 #
 """Utility functions for the connection module."""
 from __future__ import unicode_literals, print_function
-try:
-    from builtins import str, unicode  # pylint: disable=redefined-builtin
-except ImportError:
-    from builtins import str as unicode
-try:  # pragma: no cover
-    # python3
-    from urllib.parse import (urlencode as _urlencode, quote as _quote,
-                              urlparse, urlunparse, unquote as _unquote)
-except ImportError:  # pragma: no cover
-    # python2
-    from urllib import (urlencode as _urlencode, quote as _quote, unquote as
-                        _unquote)
-    from urlparse import urlparse, urlunparse
+from builtins import str as unicode
+from urllib.parse import (urlencode as _urlencode, quote as _quote,
+                          urlparse, urlunparse, unquote as _unquote)
 import re
 
 
@@ -122,7 +112,7 @@ def make_uri_path(segments=None, query=None):
 
 
 def quote(string):
-    enc = unicode(string).encode('utf-8')
+    enc = string.encode('utf-8')
     return _quote(enc).replace('/', '%2F')
 
 
@@ -136,35 +126,6 @@ def parse_url(url):
     return fullurl
 
 
-def check_python_ssl_version(hexversion):
-    """Check the python version.
-
-    If `version < 2.7.9` or `3.0 <= version < 3.2` the ssl library does not
-    actually verify the ssl certificates send by the server. That is evil and
-    these versions shall not be used.
-
-    Parameters
-    ----------
-    hexversion : int
-        A python version.
-
-    Raises
-    ------
-    Exception
-        If the version does not fully support ssl encryption.
-    """
-    if hexversion < 0x02070900:
-        raise Exception(
-            "version " + str(hex(hexversion)) +
-            "\nPython version is smaller than 2.7.9. It is not does not fully support SSL encryption. Please update your Python to 2.7.9 or greater, or 3.2 or greater."
-        )
-    elif hexversion >= 0x03000000 and hexversion < 0x03020000:
-        raise Exception(
-            "version " + str(hex(hexversion)) +
-            "\nPython 3 version is smaller than 3.2. It is not does not fully support SSL encryption. Please update your Python to 2.7.9 or greater, or 3.2 or greater."
-        )
-
-
 _PATTERN = re.compile(r"^SessionToken=([^;]*);.*$")
 
 
diff --git a/src/doc/conf.py b/src/doc/conf.py
index 8080c87b393c6684e92a98d14ac3d7a572a72cc4..9e65bff1eba5d114a77d3ed9405e883df6ad7470 100644
--- a/src/doc/conf.py
+++ b/src/doc/conf.py
@@ -29,10 +29,10 @@ copyright = '2022, IndiScale GmbH'
 author = 'Daniel Hornung'
 
 # The short X.Y version
-version = '0.7.4'
+version = '0.9.0'
 # The full version, including alpha/beta/rc tags
 # release = '0.5.2-rc2'
-release = '0.7.4'
+release = '0.9.0-dev'
 
 
 # -- General configuration ---------------------------------------------------
diff --git a/unittests/test_authentication_auth_token.py b/unittests/test_authentication_auth_token.py
index 15e54121fc0d7b5c2be645cdb88bc20804a10980..d0eb6b90883951af584d42a80e319c14891f6e50 100644
--- a/unittests/test_authentication_auth_token.py
+++ b/unittests/test_authentication_auth_token.py
@@ -65,7 +65,7 @@ def test_configure_connection():
     c._delegate_connection.resources.append(request_has_auth_token)
     assert c._authenticator.auth_token == "[request token]"
     response = c._http_request(method="GET", path="test")
-    assert response.read() == "ok"
+    assert response.read().decode() == "ok"
     assert c._authenticator.auth_token == "[response token]"
 
 
diff --git a/unittests/test_authentication_unauthenticated.py b/unittests/test_authentication_unauthenticated.py
index 52146b08ed4e1026660eebacedf348aeb2ff2721..45a709fcc62b609a97de7e87dd6c6f6ac94a55a1 100644
--- a/unittests/test_authentication_unauthenticated.py
+++ b/unittests/test_authentication_unauthenticated.py
@@ -59,7 +59,7 @@ def test_configure_connection():
 
     assert c._authenticator.auth_token is None
     response = c._http_request(method="GET", path="test")
-    assert response.read() == "ok"
+    assert response.read().decode() == "ok"
     mock.method.assert_called_once()
     assert c._authenticator.auth_token is None
 
diff --git a/unittests/test_connection.py b/unittests/test_connection.py
index 16370f00b7d5e3389582befaac1762b1d2992fcf..ee564ea033f9afc80522d75a85557f70819ece1e 100644
--- a/unittests/test_connection.py
+++ b/unittests/test_connection.py
@@ -169,7 +169,7 @@ def test_getter_status():
 def test_read():
     response = test_init_response()
     tru(hasattr(response, "read"))
-    eq(response.read(), "Body")
+    eq(response.read().decode(), "Body")
 
 
 def test_getter_session_token():