diff --git a/bob/bio/face/config/database/gbu.py b/bob/bio/face/config/database/gbu.py
deleted file mode 100644
index 31053e6f36830bcb75a0ecbab40d77cfeb6e946e..0000000000000000000000000000000000000000
--- a/bob/bio/face/config/database/gbu.py
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env python
-
-
-from bob.bio.base.pipelines.vanilla_biometrics import DatabaseConnector
-from bob.extension import rc
-from bob.bio.face.database import GBUBioDatabase
-
-
-mbgc_v1_directory = rc["bob.db.gbu.directory"]
-
-database = DatabaseConnector(
-    GBUBioDatabase(
-        original_directory=mbgc_v1_directory,
-        protocol="Good",
-        models_depend_on_protocol=True,
-        all_files_options={"subworld": "x2"},
-        extractor_training_options={"subworld": "x2"},
-        projector_training_options={"subworld": "x2"},
-        enroller_training_options={"subworld": "x2"},
-    )
-)
diff --git a/bob/bio/face/config/database/gbu_bad.py b/bob/bio/face/config/database/gbu_bad.py
new file mode 100644
index 0000000000000000000000000000000000000000..06354486d2e4336c7cdba99b257d0b02e514db1d
--- /dev/null
+++ b/bob/bio/face/config/database/gbu_bad.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+
+from bob.extension import rc
+from bob.bio.face.database import GBUDatabase
+
+
+mbgc_v1_directory = rc["bob.bio.face.gbu.directory"]
+
+database = GBUDatabase(protocol="Bad")
+
diff --git a/bob/bio/face/config/database/gbu_good.py b/bob/bio/face/config/database/gbu_good.py
new file mode 100644
index 0000000000000000000000000000000000000000..521bb9e9c453238fca3223cbe34cd63210b6a746
--- /dev/null
+++ b/bob/bio/face/config/database/gbu_good.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+
+from bob.extension import rc
+from bob.bio.face.database import GBUDatabase
+
+
+mbgc_v1_directory = rc["bob.bio.face.gbu.directory"]
+
+database = GBUDatabase(protocol="Good")
+
diff --git a/bob/bio/face/config/database/gbu_ugly.py b/bob/bio/face/config/database/gbu_ugly.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c271788e53b8098a1065d2019a42dc95ea084c3
--- /dev/null
+++ b/bob/bio/face/config/database/gbu_ugly.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+
+from bob.extension import rc
+from bob.bio.face.database import GBUDatabase
+
+
+mbgc_v1_directory = rc["bob.bio.face.gbu.directory"]
+
+database = GBUDatabase(protocol="Ugly")
+
diff --git a/bob/bio/face/database/__init__.py b/bob/bio/face/database/__init__.py
index 460ad8c804a3f6ea700604ae1b6b11bdf1c02ed4..2bcc87a10f40ce3cde46de6fd07b13a30bf6ca57 100644
--- a/bob/bio/face/database/__init__.py
+++ b/bob/bio/face/database/__init__.py
@@ -5,7 +5,7 @@ from .database import FaceBioFile
 from .mobio import MobioDatabase
 from .replay import ReplayBioDatabase
 from .atnt import AtntBioDatabase
-from .gbu import GBUBioDatabase
+from .gbu import GBUDatabase
 from .arface import ARFaceBioDatabase
 from .lfw import LFWBioDatabase
 from .multipie import MultipieDatabase
@@ -43,7 +43,7 @@ __appropriate__(
     MobioDatabase,
     ReplayBioDatabase,
     AtntBioDatabase,
-    GBUBioDatabase,
+    GBUDatabase,
     ARFaceBioDatabase,
     LFWBioDatabase,
     MultipieDatabase,
diff --git a/bob/bio/face/database/gbu.py b/bob/bio/face/database/gbu.py
index af1226d930336df245de5fb1af32356790883344..bfb0b5e37bb5d432c78f67d8409d759bc7972ecc 100644
--- a/bob/bio/face/database/gbu.py
+++ b/bob/bio/face/database/gbu.py
@@ -3,60 +3,278 @@
 # Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
 # Sat 20 Aug 15:43:10 CEST 2016
 
+from bob.bio.base.pipelines.vanilla_biometrics.abstract_classes import Database
+from bob.extension.download import search_file
+from bob.pipelines import DelayedSample, SampleSet
+import xml.sax
+import os
+from functools import partial
+from bob.extension import rc
+import bob.io.base
+
+from bob.extension.download import get_file
+
 """
-  GBU database implementation of bob.bio.base.database.ZTDatabase interface.
-  It is an extension of an SQL-based database interface, which directly talks to GBU database, for
-  verification experiments (good to use in bob.bio.base framework).
+GBU Database
+
+Several of the rules used in this code were imported from
+https://gitlab.idiap.ch/bob/bob.db.gbu/-/blob/master/bob/db/gbu/create.py
 """
 
-from .database import FaceBioFile
-from bob.bio.base.database import BioDatabase
 
+def load_annotations(annotations_file):
+    annotations = dict()
+    for i, line in enumerate(annotations_file.readlines()):
+        # Skip the first line
+        if i == 0:
+            continue
+        line = line.split(",")
+        path = os.path.splitext(os.path.basename(line[0]))[0]
+        annotations[path] = {
+            "leye": (float(line[-1]), float(line[-2])),
+            "reye": (float(line[2]), float(line[1])),
+        }
+    return annotations
+
+
+class File(object):
+    def __init__(self, subject_id, reference_id, path):
+        self.subject_id = subject_id
+        self.reference_id = reference_id
+        self.path = path
+
+
+class XmlFileReader(xml.sax.handler.ContentHandler):
+    def __init__(self):
+        self.m_signature = None
+        self.m_path = None
+        self.m_presentation = None
+        self.m_file_list = dict()
+
+    def startDocument(self):
+        pass
+
+    def endDocument(self):
+        pass
+
+    def startElement(self, name, attrs):
+        if name == "biometric-signature":
+            self.m_signature = attrs["name"]  # subject_id
+        elif name == "presentation":
+            self.m_path = os.path.splitext(attrs["file-name"])[0]  # path
+            self.m_presentation = attrs["name"]  # reference_id
+        else:
+            pass
+
+    def endElement(self, name):
+        if name == "biometric-signature":
+            # assert that everything was read correctly
+            assert (
+                self.m_signature is not None
+                and self.m_path is not None
+                and self.m_presentation is not None
+            )
+            # add a file to the sessions
+            self.m_file_list[self.m_presentation] = File(
+                subject_id_from_signature(self.m_signature),
+                self.m_presentation,
+                self.m_path,
+            )
+
+            self.m_presentation = self.m_signature = self.m_path = None
+        else:
+            pass
 
-class GBUBioFile(FaceBioFile):
 
-    def __init__(self, f):
-        super(GBUBioFile, self).__init__(client_id=f.client_id, path=f.path, file_id=f.id)
-        self._f = f
+def subject_id_from_signature(signature):
+    return int(signature[4:])
 
 
-class GBUBioDatabase(BioDatabase):
+def read_list(xml_file, eye_file=None):
+    """Reads the xml list and attaches the eye files, if given"""
+    # create xml reading instance
+    handler = XmlFileReader()
+    xml.sax.parse(xml_file, handler)
+    return handler.m_file_list
+
+
+class GBUDatabase(Database):
     """
-    GBU database implementation of :py:class:`bob.bio.base.database.BioDatabase` interface.
-    It is an extension of an SQL-based database interface, which directly talks to GBU database, for
-    verification experiments (good to use in bob.bio.base framework).
+    The GBU (Good, Bad and Ugly) database consists of parts of the MBGC-V1 image set.
+    It defines three protocols, i.e., `Good`, `Bad` and `Ugly` for which different model and probe images are used.
+
+
+    .. warning::
+      
+      To use this dataset protocol, you need to have the original files of the IJBC datasets.
+      Once you have it downloaded, please run the following command to set the path for Bob
+
+        .. code-block:: sh
+
+            bob config set bob.bio.face.gbu.directory [GBU PATH]
+
+    
+    The code below allows you to fetch the galery and probes of the "Good" protocol.
+
+    .. code-block:: python
+
+        >>> from bob.bio.face.database import GBUDatabase
+        >>> gbu = GBUDatabase(protocol="Good")
+        >>>
+        >>> # Fetching the gallery 
+        >>> references = gbu.references()
+        >>> # Fetching the probes 
+        >>> probes = gbu.probes()
+
+
     """
 
     def __init__(
-            self,
-            original_directory=None,
-            original_extension='.jpg',
-            **kwargs
+        self,
+        protocol,
+        annotation_type="eyes-center",
+        fixed_positions=None,
+        original_directory=rc.get("bob.bio.face.gbu.directory"),
+        extension=".jpg",
     ):
-        from bob.db.gbu.query import Database as LowLevelDatabase
-        self._db = LowLevelDatabase(original_directory, original_extension)
 
-        # call base class constructors to open a session to the database
-        super(GBUBioDatabase, self).__init__(
-            name='GBU',
-            original_directory=original_directory,
-            original_extension=original_extension,
-            **kwargs)
+        # self.filename = "/idiap/user/tpereira/gitlab/bob/bob.nightlies/temp/gbu.tar.gz"
+        # Downloading model if not exists
+        urls = GBUDatabase.urls()
+        self.filename = get_file(
+            "gbu-xmls.tar.gz", urls, file_hash="827de43434ee84020c6a949ece5e4a4d"
+        )
+
+        self.references_dict = {}
+        self.probes_dict = {}
+
+        self.annotations = None
+        self.original_directory = original_directory
+        self.extension = extension
+
+        self.background_samples = None
+        self._background_files = [
+            "GBU_Training_Uncontrolledx1.xml",
+            "GBU_Training_Uncontrolledx2.xml",
+            "GBU_Training_Uncontrolledx4.xml",
+            "GBU_Training_Uncontrolledx8.xml",
+        ]
+
+        super().__init__(
+            name="gbu",
+            protocol=protocol,
+            allow_scoring_with_all_biometric_references=True,
+            annotation_type="eyes-center",
+            fixed_positions=None,
+            memory_demanding=True,
+        )
+
+    @staticmethod
+    def protocols():
+        return ["Good", "Bad", "Ugly"]
+
+    @staticmethod
+    def urls():
+        return [
+            "https://www.idiap.ch/software/bob/databases/latest/gbu-xmls.tar.gz",
+            "http://www.idiap.ch/software/bob/databases/latest/gbu-xmls.tar.gz",
+        ]
+
+    def background_model_samples(self):
+        if self.background_samples is None:
+            if self.annotations is None:
+                self.annotations = load_annotations(
+                    search_file(self.filename, "alleyes.csv")
+                )
+            # for
+            self.background_samples = []
+
+            for b_files in self._background_files:
+
+                f = search_file(self.filename, f"{b_files}")
+
+                self.background_samples += self._make_sampleset_from_filedict(
+                    read_list(f)
+                )
+        return self.background_samples
+
+    def probes(self, group="dev"):
+        if self.protocol not in self.probes_dict:
+            if self.annotations is None:
+                self.annotations = load_annotations(
+                    search_file(self.filename, "alleyes.csv")
+                )
+
+            f = search_file(self.filename, f"GBU_{self.protocol}_Query.xml")
+            reference_ids = [x.reference_id for x in self.references()]
+
+            self.probes_dict[self.protocol] = self._make_sampleset_from_filedict(
+                read_list(f), reference_ids
+            )
+        return self.probes_dict[self.protocol]
+
+    def references(self, group="dev"):
+
+        if self.protocol not in self.references_dict:
+
+            if self.annotations is None:
+                self.annotations = load_annotations(
+                    search_file(self.filename, "alleyes.csv")
+                )
+
+            f = search_file(self.filename, f"GBU_{self.protocol}_Target.xml")
+            self.references_dict[self.protocol] = self._make_sampleset_from_filedict(
+                read_list(f),
+            )
+
+        return self.references_dict[self.protocol]
+
+    def groups(self):
+        return ["dev"]
+
+    def all_samples(self, group="dev"):
+        self._check_group(group)
+
+        return self.references() + self.probes()
+
+    def _check_protocol(self, protocol):
+        assert protocol in self.protocols(), "Unvalid protocol `{}` not in {}".format(
+            protocol, self.protocols()
+        )
+
+    def _check_group(self, group):
+        assert group in self.groups(), "Unvalid group `{}` not in {}".format(
+            group, self.groups()
+        )
 
-    @property
-    def original_directory(self):
-        return self._db.original_directory
+    def _make_sampleset_from_filedict(self, file_dict, reference_ids=None):
+        samplesets = []
+        for key in file_dict:
+            f = file_dict[key]
 
-    @original_directory.setter
-    def original_directory(self, value):
-        self._db.original_directory = value
+            annotations_key = os.path.basename(f.path)
 
-    def model_ids_with_protocol(self, groups=None, protocol=None, **kwargs):
-        return self._db.model_ids(groups=groups, protocol=protocol)
+            kwargs = {"references": reference_ids} if reference_ids is not None else {}
 
-    def objects(self, groups=None, protocol=None, purposes=None, model_ids=None, **kwargs):
-        retval = self._db.objects(groups=groups, protocol=protocol, purposes=purposes, model_ids=model_ids, **kwargs)
-        return [GBUBioFile(f) for f in retval]
+            samplesets.append(
+                SampleSet(
+                    key=f.path,
+                    reference_id=f.reference_id,
+                    subject_id=f.subject_id,
+                    **kwargs,
+                    samples=[
+                        DelayedSample(
+                            key=f.path,
+                            annotations=self.annotations[annotations_key],
+                            load=partial(
+                                bob.io.image.load,
+                                os.path.join(
+                                    self.original_directory, f.path + self.extension
+                                ),
+                            ),
+                        )
+                    ],
+                )
+            )
+        return samplesets
 
-    def annotations(self, myfile):
-        return self._db.annotations(myfile._f)
diff --git a/bob/bio/face/test/test_databases.py b/bob/bio/face/test/test_databases.py
index 77bc550e5e4ec8914834e64ffb04af691adadf84..0619f37ddb86c6ebec03d6396a3d7f392fced0df 100644
--- a/bob/bio/face/test/test_databases.py
+++ b/bob/bio/face/test/test_databases.py
@@ -450,3 +450,27 @@ def test_cbsr_nir_vis_2():
 
     assert len(database.references()) == 358
     assert len(database.probes()) == 6123
+
+
+@pytest.mark.skipif(
+    rc.get("bob.bio.face.gbu.directory") is None,
+    reason="GBU original protocols not available. Please do `bob config set bob.bio.face.gbu.directory [GBU PATH]` to set the GBU data path.",
+)
+def test_gbu():
+
+    from bob.bio.face.database import GBUDatabase
+
+    database = GBUDatabase("Good")
+    assert len(database.references()) == 1085
+    assert len(database.probes()) == 1085
+
+    database = GBUDatabase("Bad")
+    assert len(database.references()) == 1085
+    assert len(database.probes()) == 1085
+
+    database = GBUDatabase("Ugly")
+    assert len(database.references()) == 1085
+    assert len(database.probes()) == 1085
+
+    assert len(database.background_model_samples()) == 3910
+
diff --git a/doc/implemented.rst b/doc/implemented.rst
index f0695bc338d18329af07b3102bbc02fb8af451e7..7d7eca48710c53298d157b2c6ad226cf9ce07d0c 100644
--- a/doc/implemented.rst
+++ b/doc/implemented.rst
@@ -17,7 +17,7 @@ Databases
    bob.bio.face.database.IJBCDatabase
    bob.bio.face.database.ReplayBioDatabase
    bob.bio.face.database.ReplayMobileBioDatabase
-   bob.bio.face.database.GBUBioDatabase
+   bob.bio.face.database.GBUDatabase
    bob.bio.face.database.LFWBioDatabase
    bob.bio.face.database.MultipieDatabase
    bob.bio.face.database.FargoBioDatabase
diff --git a/setup.py b/setup.py
index 4513076e8567a61a54f96b7f800efd1613b66944..3546504ab3a168a58ca3b70f8932d626a675ab1c 100644
--- a/setup.py
+++ b/setup.py
@@ -99,7 +99,9 @@ setup(
             "atnt                     = bob.bio.face.config.database.atnt:database",
             "casia-africa             = bob.bio.face.config.database.casia_africa:database",
             "fargo                    = bob.bio.face.config.database.fargo:database",
-            "gbu                      = bob.bio.face.config.database.gbu:database",
+            "gbu-good                      = bob.bio.face.config.database.gbu_good:database",
+            "gbu-bad                      = bob.bio.face.config.database.gbu_bad:database",
+            "gbu-ugly                      = bob.bio.face.config.database.gbu_ugly:database",
             "ijbc-11                  = bob.bio.face.config.database.ijbc:database",
             "lfw-restricted           = bob.bio.face.config.database.lfw_restricted:database",
             "lfw-unrestricted         = bob.bio.face.config.database.lfw_unrestricted:database",
@@ -171,7 +173,9 @@ setup(
             "atnt                                  = bob.bio.face.config.database.atnt",
             "casia-africa                          = bob.bio.face.config.database.casia_africa",
             "fargo                                 = bob.bio.face.config.database.fargo",
-            "gbu                                   = bob.bio.face.config.database.gbu",
+            "gbu-good                              = bob.bio.face.config.database.gbu_good",
+            "gbu-bad                               = bob.bio.face.config.database.gbu_bad",
+            "gbu-ugly                              = bob.bio.face.config.database.gbu_ugly",
             "ijbc-11                               = bob.bio.face.config.database.ijbc",
             "lfw-restricted                        = bob.bio.face.config.database.lfw_restricted",
             "lfw-unrestricted                      = bob.bio.face.config.database.lfw_unrestricted",