diff --git a/deploy/all.sh b/deploy/all.sh
index c6da23366d3cd74b63fde87c3f24960c3bc2999b..254cc40c9275b5fc2c89c785a1838dac26d73ba7 100755
--- a/deploy/all.sh
+++ b/deploy/all.sh
@@ -98,6 +98,29 @@ export NATS_SECRET_NAMESPACE=${NATS_SECRET_NAMESPACE:-${TFS_K8S_NAMESPACE}}
 # If NATS_REDEPLOY is "YES", the message broker will be dropped while checking/deploying NATS.
 export NATS_REDEPLOY=${NATS_REDEPLOY:-""}
 
+# If not already set, set the namespace where QuestDB will be deployed.
+export QDB_NAMESPACE=${QDB_NAMESPACE:-"qdb"}
+
+# If not already set, set the database username to be used by Monitoring.
+export QDB_USERNAME=${QDB_USERNAME:-"admin"}
+
+# If not already set, set the database user's password to be used by Monitoring.
+export QDB_PASSWORD=${QDB_PASSWORD:-"quest"}
+
+# If not already set, set the table name to be used by Monitoring.
+export QDB_TABLE=${QDB_TABLE:-"tfs_monitoring"}
+
+## If not already set, disable flag for dropping table if exists.
+## WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE TABLE INFORMATION!
+## If QDB_DROP_TABLE_IF_EXISTS is "YES", the table pointed by variable QDB_TABLE will be dropped while
+## checking/deploying QuestDB.
+#export QDB_DROP_TABLE_IF_EXISTS=${QDB_DROP_TABLE_IF_EXISTS:-""}
+
+# If not already set, disable flag for re-deploying QuestDB from scratch.
+# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE DATABASE INFORMATION!
+# If QDB_REDEPLOY is "YES", the database will be dropped while checking/deploying QuestDB.
+export QDB_REDEPLOY=${QDB_REDEPLOY:-"YES"}
+
 
 ########################################################################################################################
 # Automated steps start here
@@ -109,6 +132,9 @@ export NATS_REDEPLOY=${NATS_REDEPLOY:-""}
 # Deploy NATS
 ./deploy/nats.sh
 
+# Deploy QuestDB
+./deploy/qdb.sh
+
 # Deploy TFS
 ./deploy/tfs.sh
 
diff --git a/deploy/crdb.sh b/deploy/crdb.sh
index 598980ac84a3b49e55402993e22ed963e80b2e38..90456773b615e9914f601133cb7da949811e06ff 100755
--- a/deploy/crdb.sh
+++ b/deploy/crdb.sh
@@ -44,7 +44,7 @@ export CRDB_DEPLOY_MODE=${CRDB_DEPLOY_MODE:-"single"}
 
 # If not already set, disable flag for dropping database if exists.
 # WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE DATABASE INFORMATION!
-# If CRDB_DROP_DATABASE_IF_EXISTS is "YES", the database pointed by variable CRDB_NAMESPACE will be dropped while
+# If CRDB_DROP_DATABASE_IF_EXISTS is "YES", the database pointed by variable CRDB_DATABASE will be dropped while
 # checking/deploying CockroachDB.
 export CRDB_DROP_DATABASE_IF_EXISTS=${CRDB_DROP_DATABASE_IF_EXISTS:-""}
 
diff --git a/deploy/qdb.sh b/deploy/qdb.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1e9d4d8ee264032a6e0073223e1363f7bf3d7910
--- /dev/null
+++ b/deploy/qdb.sh
@@ -0,0 +1,165 @@
+#!/bin/bash
+# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+########################################################################################################################
+# Read deployment settings
+########################################################################################################################
+
+# If not already set, set the namespace where QuestDB will be deployed.
+export QDB_NAMESPACE=${QDB_NAMESPACE:-"qdb"}
+
+# If not already set, set the database username to be used by Monitoring.
+export QDB_USERNAME=${QDB_USERNAME:-"admin"}
+
+# If not already set, set the database user's password to be used by Monitoring.
+export QDB_PASSWORD=${QDB_PASSWORD:-"quest"}
+
+# If not already set, set the table name to be used by Monitoring.
+export QDB_TABLE=${QDB_TABLE:-"tfs_monitoring"}
+
+## If not already set, disable flag for dropping table if exists.
+## WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE TABLE INFORMATION!
+## If QDB_DROP_TABLE_IF_EXISTS is "YES", the table pointed by variable QDB_TABLE will be dropped while
+## checking/deploying QuestDB.
+#export QDB_DROP_TABLE_IF_EXISTS=${QDB_DROP_TABLE_IF_EXISTS:-""}
+
+# If not already set, disable flag for re-deploying QuestDB from scratch.
+# WARNING: ACTIVATING THIS FLAG IMPLIES LOOSING THE DATABASE INFORMATION!
+# If QDB_REDEPLOY is "YES", the database will be dropped while checking/deploying QuestDB.
+export QDB_REDEPLOY=${QDB_REDEPLOY:-""}
+
+
+########################################################################################################################
+# Automated steps start here
+########################################################################################################################
+
+# Constants
+TMP_FOLDER="./tmp"
+QDB_MANIFESTS_PATH="manifests/questdb"
+
+# Create a tmp folder for files modified during the deployment
+TMP_MANIFESTS_FOLDER="$TMP_FOLDER/manifests"
+TMP_LOGS_FOLDER="$TMP_FOLDER/logs"
+QDB_LOG_FILE="$TMP_LOGS_FOLDER/qdb_deploy.log"
+mkdir -p $TMP_LOGS_FOLDER
+
+function qdb_deploy() {
+    echo "QuestDB Namespace"
+    echo ">>> Create QuestDB Namespace (if missing)"
+    kubectl create namespace ${QDB_NAMESPACE}
+    echo
+
+    echo "QuestDB"
+    echo ">>> Checking if QuestDB is deployed..."
+    if kubectl get --namespace ${QDB_NAMESPACE} statefulset/questdb &> /dev/null; then
+        echo ">>> QuestDB is present; skipping step."
+    else
+        echo ">>> Deploy QuestDB"
+        cp "${QDB_MANIFESTS_PATH}/manifest.yaml" "${TMP_MANIFESTS_FOLDER}/qdb_manifest.yaml"
+        kubectl apply --namespace ${QDB_NAMESPACE} -f "${TMP_MANIFESTS_FOLDER}/qdb_manifest.yaml"
+
+        echo ">>> Waiting QuestDB statefulset to be created..."
+        while ! kubectl get --namespace ${QDB_NAMESPACE} statefulset/questdb &> /dev/null; do
+            printf "%c" "."
+            sleep 1
+        done
+
+        # Wait for statefulset condition "Available=True" does not work
+        # Wait for statefulset condition "jsonpath='{.status.readyReplicas}'=3" throws error:
+        #   "error: readyReplicas is not found"
+        # Workaround: Check the pods are ready
+        #echo ">>> QuestDB statefulset created. Waiting for readiness condition..."
+        #kubectl wait --namespace  ${QDB_NAMESPACE} --for=condition=Available=True --timeout=300s statefulset/questdb
+        #kubectl wait --namespace ${QDB_NAMESPACE} --for=jsonpath='{.status.readyReplicas}'=3 --timeout=300s \
+        #    statefulset/questdb
+        echo ">>> QuestDB statefulset created. Waiting QuestDB pods to be created..."
+        while ! kubectl get --namespace ${QDB_NAMESPACE} pod/questdb-0 &> /dev/null; do
+            printf "%c" "."
+            sleep 1
+        done
+        kubectl wait --namespace ${QDB_NAMESPACE} --for=condition=Ready --timeout=300s pod/questdb-0
+    fi
+    echo
+
+    echo "QuestDB Port Mapping"
+    echo ">>> Expose QuestDB SQL port (8812->8812)"
+    QDB_SQL_PORT=$(kubectl --namespace ${QDB_NAMESPACE} get service questdb-public -o 'jsonpath={.spec.ports[?(@.name=="sql")].port}')
+    PATCH='{"data": {"'${QDB_SQL_PORT}'": "'${QDB_NAMESPACE}'/questdb-public:'${QDB_SQL_PORT}'"}}'
+    kubectl patch configmap nginx-ingress-tcp-microk8s-conf --namespace ingress --patch "${PATCH}"
+
+    PORT_MAP='{"containerPort": '${QDB_SQL_PORT}', "hostPort": '${QDB_SQL_PORT}'}'
+    CONTAINER='{"name": "nginx-ingress-microk8s", "ports": ['${PORT_MAP}']}'
+    PATCH='{"spec": {"template": {"spec": {"containers": ['${CONTAINER}']}}}}'
+    kubectl patch daemonset nginx-ingress-microk8s-controller --namespace ingress --patch "${PATCH}"
+    echo
+
+    echo ">>> Expose QuestDB Influx Line Protocol port (9009->9009)"
+    QDB_ILP_PORT=$(kubectl --namespace ${QDB_NAMESPACE} get service questdb-public -o 'jsonpath={.spec.ports[?(@.name=="ilp")].port}')
+    PATCH='{"data": {"'${QDB_ILP_PORT}'": "'${QDB_NAMESPACE}'/questdb-public:'${QDB_ILP_PORT}'"}}'
+    kubectl patch configmap nginx-ingress-tcp-microk8s-conf --namespace ingress --patch "${PATCH}"
+
+    PORT_MAP='{"containerPort": '${QDB_ILP_PORT}', "hostPort": '${QDB_ILP_PORT}'}'
+    CONTAINER='{"name": "nginx-ingress-microk8s", "ports": ['${PORT_MAP}']}'
+    PATCH='{"spec": {"template": {"spec": {"containers": ['${CONTAINER}']}}}}'
+    kubectl patch daemonset nginx-ingress-microk8s-controller --namespace ingress --patch "${PATCH}"
+    echo
+
+    echo ">>> Expose QuestDB HTTP Mgmt GUI port (9000->9000)"
+    QDB_GUI_PORT=$(kubectl --namespace ${QDB_NAMESPACE} get service questdb-public -o 'jsonpath={.spec.ports[?(@.name=="http")].port}')
+    PATCH='{"data": {"'${QDB_GUI_PORT}'": "'${QDB_NAMESPACE}'/questdb-public:'${QDB_GUI_PORT}'"}}'
+    kubectl patch configmap nginx-ingress-tcp-microk8s-conf --namespace ingress --patch "${PATCH}"
+
+    PORT_MAP='{"containerPort": '${QDB_GUI_PORT}', "hostPort": '${QDB_GUI_PORT}'}'
+    CONTAINER='{"name": "nginx-ingress-microk8s", "ports": ['${PORT_MAP}']}'
+    PATCH='{"spec": {"template": {"spec": {"containers": ['${CONTAINER}']}}}}'
+    kubectl patch daemonset nginx-ingress-microk8s-controller --namespace ingress --patch "${PATCH}"
+    echo
+}
+
+function qdb_undeploy() {
+    echo "QuestDB"
+    echo ">>> Checking if QuestDB is deployed..."
+    if kubectl get --namespace ${QDB_NAMESPACE} statefulset/questdb &> /dev/null; then
+        echo ">>> Undeploy QuestDB"
+        kubectl delete --namespace ${QDB_NAMESPACE} -f "${TMP_MANIFESTS_FOLDER}/qdb_manifest.yaml" --ignore-not-found
+    else
+        echo ">>> QuestDB is not present; skipping step."
+    fi
+    echo
+
+    echo "QuestDB Namespace"
+    echo ">>> Delete QuestDB Namespace (if exists)"
+    echo "NOTE: this step might take few minutes to complete!"
+    kubectl delete namespace ${QDB_NAMESPACE} --ignore-not-found
+    echo
+}
+
+# TODO: implement method to drop table
+#function qdb_drop_table() {
+#    echo "Drop table if exists"
+#    QDB_CLIENT_URL="postgresql://${QDB_USERNAME}:${QDB_PASSWORD}@questdb-0:${QDB_SQL_PORT}/defaultdb?sslmode=require"
+#    kubectl exec -it --namespace ${QDB_NAMESPACE} questdb-0 -- \
+#        ./qdb sql --certs-dir=/qdb/qdb-certs --url=${QDB_CLIENT_URL} \
+#        --execute "DROP TABLE IF EXISTS ${QDB_TABLE};"
+#    echo
+#}
+
+if [ "$QDB_REDEPLOY" == "YES" ]; then
+    qdb_undeploy
+#elif [ "$QDB_DROP_TABLE_IF_EXISTS" == "YES" ]; then
+#    qdb_drop_table
+fi
+qdb_deploy
diff --git a/deploy/tfs.sh b/deploy/tfs.sh
index 86043ee44829904786e700df813400476ca4e755..34ddb3903e65ccd8f32fe9428aea91c8f6a05f18 100755
--- a/deploy/tfs.sh
+++ b/deploy/tfs.sh
@@ -57,6 +57,18 @@ export CRDB_DATABASE=${CRDB_DATABASE:-"tfs"}
 # If not already set, set the namespace where NATS will be deployed.
 export NATS_NAMESPACE=${NATS_NAMESPACE:-"nats"}
 
+# If not already set, set the namespace where QuestDB will be deployed.
+export QDB_NAMESPACE=${QDB_NAMESPACE:-"qdb"}
+
+# If not already set, set the database username to be used by Monitoring.
+export QDB_USERNAME=${QDB_USERNAME:-"admin"}
+
+# If not already set, set the database user's password to be used by Monitoring.
+export QDB_PASSWORD=${QDB_PASSWORD:-"quest"}
+
+# If not already set, set the table name to be used by Monitoring.
+export QDB_TABLE=${QDB_TABLE:-"tfs_monitoring"}
+
 
 ########################################################################################################################
 # Automated steps start here
@@ -95,6 +107,22 @@ kubectl create secret generic nats-data --namespace ${TFS_K8S_NAMESPACE} --type=
     --from-literal=NATS_CLIENT_PORT=${NATS_CLIENT_PORT}
 printf "\n"
 
+echo "Create secret with QuestDB data"
+QDB_HTTP_PORT=$(kubectl --namespace ${QDB_NAMESPACE} get service questdb-public -o 'jsonpath={.spec.ports[?(@.name=="http")].port}')
+QDB_ILP_PORT=$(kubectl --namespace ${QDB_NAMESPACE} get service questdb-public -o 'jsonpath={.spec.ports[?(@.name=="ilp")].port}')
+QDB_SQL_PORT=$(kubectl --namespace ${QDB_NAMESPACE} get service questdb-public -o 'jsonpath={.spec.ports[?(@.name=="sql")].port}')
+METRICSDB_HOSTNAME="questdb-public.${QDB_NAMESPACE}.svc.cluster.local"
+kubectl create secret generic qdb-data --namespace ${TFS_K8S_NAMESPACE} --type='Opaque' \
+    --from-literal=QDB_NAMESPACE=${QDB_NAMESPACE} \
+    --from-literal=METRICSDB_HOSTNAME=${METRICSDB_HOSTNAME} \
+    --from-literal=METRICSDB_REST_PORT=${QDB_HTTP_PORT} \
+    --from-literal=METRICSDB_ILP_PORT=${QDB_ILP_PORT} \
+    --from-literal=METRICSDB_SQL_PORT=${QDB_SQL_PORT} \
+    --from-literal=METRICSDB_TABLE=${QDB_TABLE} \
+    --from-literal=METRICSDB_USERNAME=${QDB_USERNAME} \
+    --from-literal=METRICSDB_PASSWORD=${QDB_PASSWORD}
+printf "\n"
+
 echo "Deploying components and collecting environment variables..."
 ENV_VARS_SCRIPT=tfs_runtime_env_vars.sh
 echo "# Environment variables for TeraFlowSDN deployment" > $ENV_VARS_SCRIPT
@@ -251,17 +279,6 @@ for EXTRA_MANIFEST in $TFS_EXTRA_MANIFESTS; do
 done
 printf "\n"
 
-# By now, leave these controls here. Some component dependencies are not well handled.
-
-if [[ "$TFS_COMPONENTS" == *"monitoring"* ]]; then
-    echo "Waiting for 'MonitoringDB' component..."
-    # Kubernetes does not implement --for='condition=available' for statefulsets.
-    # By now, we assume a single replica of monitoringdb. To be updated in future releases.
-    kubectl wait --namespace $TFS_K8S_NAMESPACE \
-        --for=jsonpath='{.status.readyReplicas}'=1 --timeout=300s statefulset/monitoringdb
-    printf "\n"
-fi
-
 for COMPONENT in $TFS_COMPONENTS; do
     echo "Waiting for '$COMPONENT' component..."
     COMPONENT_OBJNAME=$(echo "${COMPONENT}" | sed "s/\_/-/")
@@ -274,34 +291,17 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring"
     echo "Configuring WebUI DataStores and Dashboards..."
     sleep 3
 
-    # INFLUXDB_HOST="monitoringservice"
-    # INFLUXDB_PORT=$(kubectl --namespace $TFS_K8S_NAMESPACE get service/monitoringservice -o jsonpath='{.spec.ports[?(@.name=="influxdb")].port}')
-    # INFLUXDB_URL="http://${INFLUXDB_HOST}:${INFLUXDB_PORT}"
-    # INFLUXDB_USER=$(kubectl --namespace $TFS_K8S_NAMESPACE get secrets influxdb-secrets -o jsonpath='{.data.INFLUXDB_ADMIN_USER}' | base64 --decode)
-    # INFLUXDB_PASSWORD=$(kubectl --namespace $TFS_K8S_NAMESPACE get secrets influxdb-secrets -o jsonpath='{.data.INFLUXDB_ADMIN_PASSWORD}' | base64 --decode)
-    # INFLUXDB_DATABASE=$(kubectl --namespace $TFS_K8S_NAMESPACE get secrets influxdb-secrets -o jsonpath='{.data.INFLUXDB_DB}' | base64 --decode)
-
     # Exposed through the ingress controller "tfs-ingress"
-    GRAFANA_HOSTNAME="127.0.0.1"
-    GRAFANA_PORT="80"
-    GRAFANA_BASEURL="/grafana"
+    GRAFANA_URL="127.0.0.1:80/grafana"
 
     # Default Grafana credentials
     GRAFANA_USERNAME="admin"
     GRAFANA_PASSWORD="admin"
 
-    # Default Grafana API URL
-    GRAFANA_URL_DEFAULT="http://${GRAFANA_USERNAME}:${GRAFANA_PASSWORD}@${GRAFANA_HOSTNAME}:${GRAFANA_PORT}${GRAFANA_BASEURL}"
-
-    # Updated Grafana API URL
-    GRAFANA_URL_UPDATED="http://${GRAFANA_USERNAME}:${TFS_GRAFANA_PASSWORD}@${GRAFANA_HOSTNAME}:${GRAFANA_PORT}${GRAFANA_BASEURL}"
-
-    echo "export GRAFANA_URL_UPDATED=${GRAFANA_URL_UPDATED}" >> $ENV_VARS_SCRIPT
-
-    echo "Connecting to grafana at URL: ${GRAFANA_URL_DEFAULT}..."
-
     # Configure Grafana Admin Password
     # Ref: https://grafana.com/docs/grafana/latest/http_api/user/#change-password
+    GRAFANA_URL_DEFAULT="http://${GRAFANA_USERNAME}:${GRAFANA_PASSWORD}@${GRAFANA_URL}"
+    echo "Connecting to grafana at URL: ${GRAFANA_URL_DEFAULT}..."
     curl -X PUT -H "Content-Type: application/json" -d '{
         "oldPassword": "'${GRAFANA_PASSWORD}'",
         "newPassword": "'${TFS_GRAFANA_PASSWORD}'",
@@ -309,16 +309,21 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring"
     }' ${GRAFANA_URL_DEFAULT}/api/user/password
     echo
 
+    # Updated Grafana API URL
+    GRAFANA_URL_UPDATED="http://${GRAFANA_USERNAME}:${TFS_GRAFANA_PASSWORD}@${GRAFANA_URL}"
+    echo "export GRAFANA_URL_UPDATED=${GRAFANA_URL_UPDATED}" >> $ENV_VARS_SCRIPT
+
     # Ref: https://grafana.com/docs/grafana/latest/http_api/data_source/
     # TODO: replace user, password and database by variables to be saved
+    QDB_HOST_PORT="${METRICSDB_HOSTNAME}:${QDB_SQL_PORT}"
     echo "Creating a datasource..."
     curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" -d '{
         "access"   : "proxy",
         "type"     : "postgres",
-        "name"     : "monitoringdb",
-        "url"      : "monitoringservice:8812",
-        "database" : "monitoring",
-        "user"     : "admin",
+        "name"     : "questdb",
+        "url"      : "'${QDB_HOST_PORT}'",
+        "database" : "'${QDB_TABLE}'",
+        "user"     : "'${QDB_USERNAME}'",
         "basicAuth": false,
         "isDefault": true,
         "jsonData" : {
@@ -333,9 +338,7 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring"
             "tlsConfigurationMethod": "file-path",
             "tlsSkipVerify"         : true
         },
-        "secureJsonData": {
-            "password": "quest"
-        }
+        "secureJsonData": {"password": "'${QDB_PASSWORD}'"}
     }' ${GRAFANA_URL_UPDATED}/api/datasources
     echo
 
@@ -352,4 +355,3 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring"
 
     printf "\n\n"
 fi
-