diff --git a/CHANGELOG.md b/CHANGELOG.md
index 485e806bd957d5cc8b8a314c3661e707c5ca6378..b5fe7680ae1ec2f68631826fe246c539a1de036a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * Basic functionality to establish connection to a CaosDB server and
   retrieve its version (using the Extern C interface of caosdb-cpplib)
 * Support for Windows
+* Support for config files
+* Minimal error handling
 
 ### Changed
 
diff --git a/HUMANS.md b/HUMANS.md
index 66ee100df5c191da88717f9c96faaf7ce736dc41..5b0e914eddb78f8c5ccd69cd89c58c57b1c5687e 100644
--- a/HUMANS.md
+++ b/HUMANS.md
@@ -1,3 +1,4 @@
 # Active Contributors
 
+* Alexander Kreft
 * Florian Spreckelsen <f.spreckelsen@indiscale.com>
diff --git a/Manifest.toml b/Manifest.toml
index f45eecff031feeb9bb67f87c4794b44cc53a293d..663c54166d2aec89522e49737d9c75683f2ecf74 100644
--- a/Manifest.toml
+++ b/Manifest.toml
@@ -1,2 +1,7 @@
 # This file is machine-generated - editing it directly is not advised
 
+[[Libdl]]
+uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
+
+[[Logging]]
+uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
diff --git a/Project.toml b/Project.toml
index a389dd0b783b124879da8597b3f6b5215beb4481..a17b1d50149fa14067e15ab9c8523b4b3cdbbafb 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,4 +1,8 @@
 name = "CaosDB"
 uuid = "091fdcf5-a163-4d8f-97f4-9adce40cd04e"
 authors = ["florian <f.spreckelsen@inidscale.com>"]
-version = "0.0.1"
+version = "0.0.2"
+
+[deps]
+Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
+Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
diff --git a/README.md b/README.md
index b02135c295d186b9aa988157e4ab9cb33409b936..3fadc0c69386b1db306dec85cfc4c3a5550c00f2 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,9 @@ client library for CaosDB and a part of the CaosDB project.
 ## Setup
 
 Please read the [README\_SETUP.md](README_SETUP.md) for instructions
-on how to develop, build, and use this code.
+on how to develop, build, and use this code. caosdb-julialib is
+developped and tested using Julia 1.6, we cannot guarantee its
+compatibility with versions <= 1.5.
 
 ## Further reading
 
diff --git a/src/CaosDB.jl b/src/CaosDB.jl
index f8bf67eb4593ee58e0bc8d49dfcd776ae6b616ed..906400025ea1e789254dcb8539c1600be3aebf1a 100644
--- a/src/CaosDB.jl
+++ b/src/CaosDB.jl
@@ -3,6 +3,7 @@
 #
 # Copyright (C) 2021 Indiscale GmbH <info@indiscale.com>
 # Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com>
+# Copyright (C) 2021 Alexander Kreft
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as
@@ -23,10 +24,75 @@
 
 module CaosDB
 
+using Libdl
+
 """
 Chose the name of the library according to the OS you're running.
 """
 library_name = (@static Sys.iswindows() ? "ccaosdb" : "libccaosdb")
+if isempty(find_library(library_name))
+    @error "Could not find $library_name"
+end
+
+module Exceptions
+
+export evaluate_return_code, CaosDBException, GenericCaosDBException, CaosDBMessage
+
+using Logging
+using CaosDB
+
+"""
+The parent type of all CaosDB errors that can also be used for testing.
+"""
+abstract type CaosDBException <: Exception end
+
+"""
+A generic exception that will be raised in case of non-zero return
+values of the calls to libccaosdb. May carry a message string and a
+code.
+"""
+struct GenericCaosDBException <: CaosDBException
+    msg::String
+    code::Cint
+end
+
+Base.showerror(io::IO, e::CaosDBException) =
+    print(io, "CaosDBException: ", e.msg, " (Status code ", e.code, ")")
+
+"""
+Struct containing Messages and codes for status codes<0 that do not
+correspond to errors or success.
+"""
+struct CaosDBMessage
+    msg::String
+    code::Cint
+end
+
+Base.show(io::IO, m::CaosDBMessage) = print(io, m.msg, " (Status code ", m.code, ")")
+
+"""
+    function evaluate_return_code(code::Cint)
+
+Evaluate the return code of a libccaosdb ccall and raise a
+`GenericCaosDBException` in case of a non-zero return code.
+"""
+function evaluate_return_code(code::Cint)
+    if code != 0
+        msg = ccall(
+            (:caosdb_get_status_description, CaosDB.library_name),
+            Cstring,
+            (Cint,),
+            code,
+        )
+        if code > 0
+            throw(GenericCaosDBException(unsafe_string(msg), code))
+        else
+            @info CaosDBMessage(unsafe_string(msg), code)
+        end
+    end
+end
+
+end # Exceptions
 
 module Info
 
@@ -92,13 +158,13 @@ authenticator object from a configuration.
 mutable struct _Authenticator
     wrapped_authenticator::Ptr{Cvoid}
 
-    function _Authenticator()
+    function _Authenticator(managed_by_julia::Bool = false)
         auth = new()
-        # force this to point to C_NULL after initialization
-        auth.wrapped_authenticator = C_NULL
-        function f(t)
-            if t.wrapped_authenticator != C_NULL
-                # Only if pointer was filled after real initialization
+        if managed_by_julia
+            # Only append a finalizer for this if the object is
+            # actually managed by Julia and not created and destroyed
+            # internally by libcaosdb.
+            function f(t)
                 ccall(
                     (:caosdb_authentication_delete_authenticator, CaosDB.library_name),
                     Cint,
@@ -106,8 +172,9 @@ mutable struct _Authenticator
                     Ref{_Authenticator}(t),
                 )
             end
+            finalizer(f, auth)
         end
-        finalizer(f, auth)
+        return auth
     end
 end
 
@@ -126,7 +193,7 @@ function create_plain_password_authenticator(
     password::AbstractString,
 )
 
-    auth = Ref{_Authenticator}(_Authenticator())
+    auth = Ref{_Authenticator}(_Authenticator(true))
 
     err_code = ccall(
         (:caosdb_authentication_create_plain_password_authenticator, CaosDB.library_name),
@@ -137,11 +204,7 @@ function create_plain_password_authenticator(
         password,
     )
 
-    if err_code != 0
-
-        @error "Creating authenticator failed with code $err_code"
-
-    end
+    CaosDB.Exceptions.evaluate_return_code(err_code)
 
     return auth
 
@@ -149,365 +212,7 @@ end
 
 end # Authentication
 
-module Connection
-
-using ..CaosDB
-
-export connect
-
-"""
-Struct containing the actual connection to a CaosDB server. Meant for
-internal use; call a `CaosDB.Connection.create_<connection>` function
-to create an connection object from a configuration.
-"""
-mutable struct _Connection
-    wrapped_connection::Ptr{Cvoid}
-
-    function _Connection()
-        conn = new()
-        conn.wrapped_connection = C_NULL
-        function f(t)
-            if t.wrapped_connection != C_NULL
-                ccall(
-                    (:caosdb_connection_delete_connection, CaosDB.library_name),
-                    Cint,
-                    (Ref{_Connection},),
-                    Ref{_Connection}(t),
-                )
-            end
-        end
-        finalizer(f, conn)
-    end
-end
-
-"""
-Struct containing a pointer to the wrapped cpp class providing the
-certificate provider. Meant for internal use; call a
-`CaosDB.Connection.create_<certificate_provider>` function to create
-an certificate-provider object from a configuration.
-"""
-mutable struct _CertificateProvider
-    wrapped_certificate_provider::Ptr{Cvoid}
-
-    function _CertificateProvider()
-        prov = new()
-        prov.wrapped_certificate_provider = C_NULL
-        function f(t)
-            if t.wrapped_certificate_provider != C_NULL
-                ccall(
-                    (:caosdb_connection_delete_certificate_provider, CaosDB.library_name),
-                    Cint,
-                    (Ref{_CertificateProvider},),
-                    Ref{_CertificateProvider}(t),
-                )
-            end
-        end
-        finalizer(f, prov)
-    end
-end
-
-"""
-Struct containing a pointer to the wrapped cpp class for storing the
-connection configuration. Meant for internal use; call a
-`CaosDB.Connection.create_<configuration>` function to create
-an connection-configuration object from a configuration.
-"""
-mutable struct _Configuration
-    wrapped_connection_configuration::Ptr{Cvoid}
-
-    function _Configuration()
-        config = new()
-        config.wrapped_connection_configuration = C_NULL
-        function f(t)
-            if t.wrapped_connection_configuration != C_NULL
-                ccall(
-                    (
-                        :caosdb_connection_delete_connection_configuration,
-                        CaosDB.library_name,
-                    ),
-                    Cint,
-                    (Ref{_Configuration},),
-                    Ref{_Configuration}(t),
-                )
-            end
-        end
-        finalizer(f, config)
-    end
-end
-
-"""
-    create_pem_file_certificate_provider(path::AbstractString)
-
-Return a `_CertificateProvider` for the pem certificate located at
-`path`.
-"""
-function create_pem_file_certificate_provider(path::AbstractString)
-
-    cert_provider = Ref{_CertificateProvider}(_CertificateProvider())
-
-    err_code = ccall(
-        (:caosdb_connection_create_pem_file_certificate_provider, CaosDB.library_name),
-        Cint,
-        (Ref{_CertificateProvider}, Cstring),
-        cert_provider,
-        path,
-    )
-
-    if err_code != 0
-
-        @error "PEM certificate creation returned code $err_code."
-
-    end
-
-    return cert_provider
-
-end
-
-"""
-    create_tls_connection_configuration(
-        host::AbstractString,
-        port::Cint,
-        authenticator::Ref{CaosDB.Authentication._Authenticator},
-        provider::Ref{_CertificateProvider}
-        )
-
-Return a TLS connection configuration with authentication.
-"""
-function create_tls_connection_configuration(
-    host::AbstractString,
-    port::Cint,
-    authenticator::Ref{CaosDB.Authentication._Authenticator},
-    provider::Ref{_CertificateProvider},
-)
-
-    config = Ref{_Configuration}(_Configuration())
-
-    err_code = ccall(
-        (:caosdb_connection_create_tls_connection_configuration, CaosDB.library_name),
-        Cint,
-        (
-            Ref{_Configuration},
-            Cstring,
-            Cint,
-            Ref{CaosDB.Authentication._Authenticator},
-            Ref{_CertificateProvider},
-        ),
-        config,
-        host,
-        port,
-        authenticator,
-        provider,
-    )
-
-    if err_code != 0
-
-        @error "TLS-configuration creation returned code $err_code."
-
-    end
-
-    return config
-
-end
-
-function create_insecure_connection_configuration(host::AbstractString, port::Cint)
-
-    config = Ref{_Configuration}(_Configuration())
-
-    err_code = ccall(
-        (:caosdb_connection_create_insecure_connection_configuration, CaosDB.library_name),
-        Cint,
-        (Ref{_Configuration}, Cstring, Cint),
-        config,
-        host,
-        port,
-    )
-
-    if err_code != 0
-
-        @error "Insecure configuration creation returned code $err_code."
-
-    end
-
-    return config
-end
-
-"""
-    create_connection(config::Ref{_Configuration})
-
-Return a connection based on the given `config`.
-"""
-function create_connection(config::Ref{_Configuration})
-
-    connection = Ref{_Connection}(_Connection())
-
-    err_code = ccall(
-        (:caosdb_connection_create_connection, CaosDB.library_name),
-        Cint,
-        (Ref{_Connection}, Ref{_Configuration}),
-        connection,
-        config,
-    )
-
-    if err_code != 0
-
-        @error "Creating connection failed with code $err_code."
-
-    end
-
-    return connection
-
-end
-
-"""
-    get_version_info(con::Ref{_Connection})
-
-Return the version of the CaosDB server that `con` is connected
-to.
-"""
-function get_version_info(con::Ref{_Connection})
-
-    info = Ref{CaosDB.Info._VersionInfo}(CaosDB.Info._VersionInfo())
-
-    err_code = ccall(
-        (:caosdb_connection_get_version_info, CaosDB.library_name),
-        Cint,
-        (Ref{CaosDB.Info._VersionInfo}, Ref{_Connection}),
-        info,
-        con,
-    )
-
-    # TODO Real error-code handling
-    if err_code != 0
-
-        @error "Version info returned with code $err_code"
-
-    end
-
-    return info
-
-end
-
-"""
-    print_version_info(con::Ref{_Connection})
-
-Retrieve the version info for the CaosDB server `con` is connected to,
-and print the version in a nice message.
-"""
-function print_version_info(con::Ref{_Connection})
-
-    # Dereference to access the fields
-    info = get_version_info(con)[]
-
-    major = info.major
-    minor = info.minor
-    patch = info.patch
-    pre_release_str = unsafe_string(info.pre_release)
-    build_str = unsafe_string(info.build)
-
-    println(
-        "Connected to a CaosDB server with version $major.$minor.$patch-$pre_release_str-$build_str.",
-    )
-
-end
-
-"""
-    function connect([;
-        host::AbstractString="",
-        port_str::AbstractString="undefined",
-        cacert::AbstractString="",
-        username::AbstractString="",
-        password::AbstractString="undefined"]
-    )
-
-Return a connection object created for the given `host`:`port` with an
-SSL certificate located at `cacert` with the given credentials.
-
-# Extended help
-
-!!! info
-
-    Because of type-stability, and since an empty string may be a
-    valid password, the value of `password`, for which it is fetched
-    from an environmental variable, is "undefined". This means that if
-    you absolutely must use "undefined" as your password, you have to
-    specify it via the `CAOSDB_PASSWORD` variable.
-
-# Arguments
-- `host::AbstractString=""`: The hostname of the CaosDB server. If
-  none is provided, the `CAOSDB_SERVER_HOST` environmental variable is
-  used instead. If that's not defined, "localhost" is used.
-- `port_str::AbstractString="undefined"`: The port of the CaosDB
-  server, given as string. If none is provided, the
-  `CAOSDB_SERVER_GRPC_PORT_HTTPS` environmental variable is used
-  instead. If that's not defined, "8443" is used. The default value is
-  "undefined" rather than an empty string because an empty string
-  could be a valid port, too, i.e. the CaosDB server is available at
-  `host` without a port.
-- `cacert::AbstractString=""`: The path to the SSL certificate of the
-  CaosDB server. If none is provided, the `CAOSDB_SERVER_CERT`
-  environmental variable is used instead.
-- `username::AbstractString=""`: The username with which to log in
-  into the CaosDB server. If none is provided, the `CAOSDB_USER`
-  environmental variable is used instead. If that's not defined,
-  "admin" is used.
-- `password::AbstractString="undefined"`: The password with which to
-  log in into the CaosDB server. If none is provided, the
-  `CAOSDB_PASSWORD` environmental variable is used instead. If that's
-  not defined, "caosdb" is used. The default value is "undefined"
-  rather than an empty string to allow an empty password.
-"""
-function connect(;
-    host::AbstractString = "",
-    port_str::AbstractString = "undefined",
-    cacert::AbstractString = "",
-    username::AbstractString = "",
-    password::AbstractString = "undefined",
-)
-
-    if host == ""
-
-        host = CaosDB.Utility.get_env_var("CAOSDB_SERVER_HOST", "localhost")
-
-    end
-
-    if port_str == "undefined"
-
-        port_str = CaosDB.Utility.get_env_var("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443")
-
-    end
-
-    port = parse(Cint, port_str)
-
-    if cacert == ""
-
-        cacert = CaosDB.Utility.get_env_var("CAOSDB_SERVER_CERT")
-
-    end
-
-    if username == ""
-
-        username = CaosDB.Utility.get_env_var("CAOSDB_USER", "admin")
-
-    end
-
-    if password == "undefined"
-
-        password = CaosDB.Utility.get_env_var("CAOSDB_PASSWORD", "caosdb")
-
-    end
-
-    provider = create_pem_file_certificate_provider(cacert)
-    authenticator =
-        CaosDB.Authentication.create_plain_password_authenticator(username, password)
-    config = create_tls_connection_configuration(host, port, authenticator, provider)
-    connection = create_connection(config)
-    print_version_info(connection)
-
-    return connection
-
-end
-
-end # Connection
+include("Connection.jl")
 
 module Entity end
 
diff --git a/src/Connection.jl b/src/Connection.jl
new file mode 100644
index 0000000000000000000000000000000000000000..0f8e140a682e1e269b4ee395507b1ce66e54220a
--- /dev/null
+++ b/src/Connection.jl
@@ -0,0 +1,423 @@
+# ** header v3.0
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2021 Indiscale GmbH <info@indiscale.com>
+# Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com>
+#
+# 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
+#
+
+module Connection
+
+using ..CaosDB
+
+export connect, connect_manually
+
+"""
+Struct containing the actual connection to a CaosDB server. Meant for
+internal use; call a `CaosDB.Connection.create_<connection>` function
+to create an connection object from a configuration.
+"""
+mutable struct _Connection
+    wrapped_connection::Ptr{Cvoid}
+
+    function _Connection(managed_by_julia::Bool = false)
+        conn = new()
+        if managed_by_julia
+            # Only append a finalizer for this if the object is
+            # actually managed by Julia and not created and destroyed
+            # internally by libcaosdb.
+            function f(t)
+                ccall(
+                    (:caosdb_connection_delete_connection, CaosDB.library_name),
+                    Cint,
+                    (Ref{_Connection},),
+                    Ref{_Connection}(t),
+                )
+            end
+            finalizer(f, conn)
+        end
+        return conn
+    end
+end
+
+"""
+Struct containing a pointer to the wrapped cpp class providing the
+certificate provider. Meant for internal use; call a
+`CaosDB.Connection.create_<certificate_provider>` function to create
+an certificate-provider object from a configuration.
+"""
+mutable struct _CertificateProvider
+    wrapped_certificate_provider::Ptr{Cvoid}
+
+    function _CertificateProvider(managed_by_julia::Bool = false)
+        prov = new()
+        if managed_by_julia
+            # Only append a finalizer for this if the object is
+            # actually managed by Julia and not created and destroyed
+            # internally by libcaosdb.
+            function f(t)
+                ccall(
+                    (:caosdb_connection_delete_certificate_provider, CaosDB.library_name),
+                    Cint,
+                    (Ref{_CertificateProvider},),
+                    Ref{_CertificateProvider}(t),
+                )
+            end
+            finalizer(f, prov)
+        end
+        return prov
+    end
+end
+
+"""
+Struct containing a pointer to the wrapped cpp class for storing the
+connection configuration. Meant for internal use; call a
+`CaosDB.Connection.create_<configuration>` function to create
+an connection-configuration object from a configuration.
+"""
+mutable struct _Configuration
+    wrapped_connection_configuration::Ptr{Cvoid}
+
+    function _Configuration(managed_by_julia::Bool = false)
+        config = new()
+        if managed_by_julia
+            # Only append a finalizer for this if the object is
+            # actually managed by Julia and not created and destroyed
+            # internally by libcaosdb.
+            function f(t)
+                ccall(
+                    (
+                        :caosdb_connection_delete_connection_configuration,
+                        CaosDB.library_name,
+                    ),
+                    Cint,
+                    (Ref{_Configuration},),
+                    Ref{_Configuration}(t),
+                )
+            end
+            finalizer(f, config)
+        end
+        return config
+    end
+end
+
+"""
+    create_pem_file_certificate_provider(path::AbstractString)
+
+Return a `_CertificateProvider` for the pem certificate located at
+`path`.
+"""
+function create_pem_file_certificate_provider(path::AbstractString)
+
+    cert_provider = Ref{_CertificateProvider}(_CertificateProvider(true))
+
+    err_code = ccall(
+        (:caosdb_connection_create_pem_file_certificate_provider, CaosDB.library_name),
+        Cint,
+        (Ref{_CertificateProvider}, Cstring),
+        cert_provider,
+        path,
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return cert_provider
+
+end
+
+"""
+    create_tls_connection_configuration(
+        host::AbstractString,
+        port::Cint,
+        authenticator::Ref{CaosDB.Authentication._Authenticator},
+        provider::Ref{_CertificateProvider}
+        )
+
+Return a TLS connection configuration with authentication.
+"""
+function create_tls_connection_configuration(
+    host::AbstractString,
+    port::Cint,
+    authenticator::Ref{CaosDB.Authentication._Authenticator},
+    provider::Ref{_CertificateProvider},
+)
+
+    config = Ref{_Configuration}(_Configuration(true))
+
+    err_code = ccall(
+        (:caosdb_connection_create_tls_connection_configuration, CaosDB.library_name),
+        Cint,
+        (
+            Ref{_Configuration},
+            Cstring,
+            Cint,
+            Ref{CaosDB.Authentication._Authenticator},
+            Ref{_CertificateProvider},
+        ),
+        config,
+        host,
+        port,
+        authenticator,
+        provider,
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return config
+
+end
+
+function create_insecure_connection_configuration(host::AbstractString, port::Cint)
+
+    config = Ref{_Configuration}(_Configuration(true))
+
+    err_code = ccall(
+        (:caosdb_connection_create_insecure_connection_configuration, CaosDB.library_name),
+        Cint,
+        (Ref{_Configuration}, Cstring, Cint),
+        config,
+        host,
+        port,
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return config
+end
+
+"""
+    create_connection(config::Ref{_Configuration})
+
+Return a connection based on the given `config`.
+"""
+function create_connection(config::Ref{_Configuration})
+
+    connection = Ref{_Connection}(_Connection(true))
+
+    err_code = ccall(
+        (:caosdb_connection_create_connection, CaosDB.library_name),
+        Cint,
+        (Ref{_Connection}, Ref{_Configuration}),
+        connection,
+        config,
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return connection
+
+end
+
+
+function get_connection(name::AbstractString = "default")
+
+    connection = Ref{_Connection}(_Connection())
+
+    if name == "default"
+        err_code = ccall(
+            (
+                :caosdb_connection_connection_manager_get_default_connection,
+                CaosDB.library_name,
+            ),
+            Cint,
+            (Ref{_Connection},),
+            connection,
+        )
+    else
+        err_code = ccall(
+            (:caosdb_connection_connection_manager_get_connection, CaosDB.library_name),
+            Cint,
+            (Ref{_Connection}, Cstring),
+            connection,
+            name,
+        )
+    end
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return connection
+
+end
+
+
+"""
+    get_version_info(con::Ref{_Connection})
+
+Return the version of the CaosDB server that `con` is connected
+to.
+"""
+function get_version_info(con::Ref{_Connection})
+
+    info = Ref{CaosDB.Info._VersionInfo}(CaosDB.Info._VersionInfo())
+
+    err_code = ccall(
+        (:caosdb_connection_get_version_info, CaosDB.library_name),
+        Cint,
+        (Ref{CaosDB.Info._VersionInfo}, Ref{_Connection}),
+        info,
+        con,
+    )
+
+    CaosDB.Exceptions.evaluate_return_code(err_code)
+
+    return info
+
+end
+
+"""
+    print_version_info(con::Ref{_Connection})
+
+Retrieve the version info for the CaosDB server `con` is connected to,
+and print the version in a nice message.
+"""
+function print_version_info(con::Ref{_Connection})
+
+    # Dereference to access the fields
+    info = get_version_info(con)[]
+
+    major = info.major
+    minor = info.minor
+    patch = info.patch
+    pre_release_str = unsafe_string(info.pre_release)
+    build_str = unsafe_string(info.build)
+
+    println(
+        "Connected to a CaosDB server with version $major.$minor.$patch-$pre_release_str-$build_str.",
+    )
+
+end
+
+"""
+    function connect_manually([;
+        host::AbstractString="",
+        port_str::AbstractString="undefined",
+        cacert::AbstractString="",
+        username::AbstractString="",
+        password::AbstractString="undefined"]
+    )
+
+Return a connection object created for the given `host`:`port` with an
+SSL certificate located at `cacert` with the given credentials.
+
+# Extended help
+
+!!! info
+
+    Because of type-stability, and since an empty string may be a
+    valid password, the value of `password`, for which it is fetched
+    from an environmental variable, is "undefined". This means that if
+    you absolutely must use "undefined" as your password, you have to
+    specify it via the `CAOSDB_PASSWORD` variable.
+
+# Arguments
+- `host::AbstractString=""`: The hostname of the CaosDB server. If
+  none is provided, the `CAOSDB_SERVER_HOST` environmental variable is
+  used instead. If that's not defined, "localhost" is used.
+- `port_str::AbstractString="undefined"`: The port of the CaosDB
+  server, given as string. If none is provided, the
+  `CAOSDB_SERVER_GRPC_PORT_HTTPS` environmental variable is used
+  instead. If that's not defined, "8443" is used. The default value is
+  "undefined" rather than an empty string because an empty string
+  could be a valid port, too, i.e. the CaosDB server is available at
+  `host` without a port.
+- `cacert::AbstractString=""`: The path to the SSL certificate of the
+  CaosDB server. If none is provided, the `CAOSDB_SERVER_CERT`
+  environmental variable is used instead.
+- `username::AbstractString=""`: The username with which to log in
+  into the CaosDB server. If none is provided, the `CAOSDB_USER`
+  environmental variable is used instead. If that's not defined,
+  "admin" is used.
+- `password::AbstractString="undefined"`: The password with which to
+  log in into the CaosDB server. If none is provided, the
+  `CAOSDB_PASSWORD` environmental variable is used instead. If that's
+  not defined, "caosdb" is used. The default value is "undefined"
+  rather than an empty string to allow an empty password.
+"""
+function connect_manually(;
+    host::AbstractString = "",
+    port_str::AbstractString = "undefined",
+    cacert::AbstractString = "",
+    username::AbstractString = "",
+    password::AbstractString = "undefined",
+)
+
+    if host == ""
+
+        host = CaosDB.Utility.get_env_var("CAOSDB_SERVER_HOST", "localhost")
+
+    end
+
+    if port_str == "undefined"
+
+        port_str = CaosDB.Utility.get_env_var("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443")
+
+    end
+
+    port = parse(Cint, port_str)
+
+    if cacert == ""
+
+        cacert = CaosDB.Utility.get_env_var("CAOSDB_SERVER_CERT")
+
+    end
+
+    if username == ""
+
+        username = CaosDB.Utility.get_env_var("CAOSDB_USER", "admin")
+
+    end
+
+    if password == "undefined"
+
+        password = CaosDB.Utility.get_env_var("CAOSDB_PASSWORD", "caosdb")
+
+    end
+
+    provider = create_pem_file_certificate_provider(cacert)
+    authenticator =
+        CaosDB.Authentication.create_plain_password_authenticator(username, password)
+    config = create_tls_connection_configuration(host, port, authenticator, provider)
+    connection = create_connection(config)
+    print_version_info(connection)
+
+    return connection
+
+end
+
+"""
+    connect(name::AbstractString="default")
+
+Create a connection with name `name` from your configuration file,
+print the version of the server the connection is established to, and
+return the connection object.
+
+# Arguments
+
+- name::AbstractString="default": The name of the configuration
+  defined in your config json that will be used to connect to the
+  CaosDB server defined therein. Default value is "default".
+"""
+function connect(name::AbstractString = "default")
+    conn = get_connection(name)
+
+    print_version_info(conn)
+
+    return conn
+end
+
+end # Connection
diff --git a/test/runtests.jl b/test/runtests.jl
index 148514976253884a6426d6d858a6d7154bf12dc0..5fa1db168735cfad9532752b8d9d3364074e447b 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -23,9 +23,45 @@
 using Test
 using CaosDB
 
-if haskey(ENV, "SHELL")
-    shell_var = ENV["SHELL"]
-else
-    shell_var = "default"
+@testset "CaosDBUnitTests" begin
+    @testset "TestUtility" begin
+        if haskey(ENV, "SHELL")
+            shell_var = ENV["SHELL"]
+        else
+            shell_var = "default"
+        end
+        @test CaosDB.Utility.get_env_var("SHELL", "default") == shell_var
+    end
+
+    @testset "TestExceptions" begin
+        # In case of success, nothing is done
+        @test CaosDB.Exceptions.evaluate_return_code(Cint(0)) == nothing
+
+        # CaosDBExceptions are thrown for return codes > 0
+        @test_throws CaosDB.Exceptions.CaosDBException CaosDB.Exceptions.evaluate_return_code(
+            Cint(14),
+        )
+        @test_throws CaosDB.Exceptions.GenericCaosDBException CaosDB.Exceptions.evaluate_return_code(
+            Cint(14),
+        )
+        try
+            CaosDB.Exceptions.evaluate_return_code(Cint(14))
+            # fail if this doesn't throw an error
+            @test false
+        catch e
+            @test isa(e, CaosDB.Exceptions.GenericCaosDBException)
+            @test e.code == 14
+        end
+
+        # Return codes < 0 correspond to unfinished transactions and
+        # we expect messages to be returned.
+        @test CaosDB.Exceptions.evaluate_return_code(Cint(-1)) == nothing
+        @test_logs (
+            :info,
+            CaosDB.Exceptions.CaosDBMessage(
+                "The transaction is currently being executed.",
+                Cint(-1),
+            ),
+        ) CaosDB.Exceptions.evaluate_return_code(Cint(-1))
+    end
 end
-@test CaosDB.Utility.get_env_var("SHELL", "default") == shell_var