diff --git a/.github/workflows/ansible-test-plugins.yml b/.github/workflows/ansible-test-plugins.yml
index 4622dbe..88d8fce 100644
--- a/.github/workflows/ansible-test-plugins.yml
+++ b/.github/workflows/ansible-test-plugins.yml
@@ -1,3 +1,4 @@
+---
 name: Plugins CI
 on:
   push:
@@ -14,10 +15,6 @@ on:
     - cron: '0 6 * * *'
 
 
-env:
-  mysql_version_file: "tests/integration/targets/setup_mysql/defaults/main.yml"
-  connector_version_file: "tests/integration/targets/setup_mysql/vars/main.yml"
-
 jobs:
   sanity:
     name: "Sanity (Ansible: ${{ matrix.ansible }})"
@@ -43,42 +40,312 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        db_engine_version:
-          - mysql_5.7.31
-          - mysql_8.0.22
-        ansible:
-          - stable-2.12
-          - stable-2.13
-          - stable-2.14
-          - devel
-        python:
-          - 3.6
-          - 3.8
-          - 3.9
-        connector:
-          - pymysql==0.7.10
-          - pymysql==0.9.3
-          - mysqlclient==2.0.1
-        exclude:
-          - db_engine_version: mysql_8.0.22
-            connector: pymysql==0.7.10
-          - python: 3.6
-            ansible: stable-2.12
-          - python: 3.6
-            ansible: stable-2.13
-          - python: 3.6
-            ansible: stable-2.14
-          - python: 3.6
-            ansible: devel
-          - python: 3.8
-            ansible: stable-2.13
-          - python: 3.8
-            ansible: stable-2.14
-          - python: 3.8
-            ansible: devel
-          - python: 3.9
-            ansible: stable-2.12
+        include:
+          # Before we can activate test with pymysql 1.0.2 we should debug the
+          # following plugins:
+          #
+          # mysql_query:
+          # test "Assert that create table IF NOT EXISTS is not changed with pymysql" failed
+          #
+          # mysql_replication:
+          # test "Assert that startreplica is not changed" failed
+
+          # ==================================================================
+          # mysql-client 5.7 + Python 3.8
+          # ==================================================================
+          - ansible: stable-2.12
+            db_engine_version: mysql:5.7.40
+            python: '3.8'
+            connector: pymysql==0.7.11
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my57-py38-pymysql0711:latest
+          - ansible: stable-2.12
+            db_engine_version: mysql:5.7.40
+            python: '3.8'
+            connector: pymysql==0.9.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my57-py38-pymysql093:latest
+          - ansible: stable-2.12
+            db_engine_version: mysql:5.7.40
+            python: '3.8'
+            connector: mysqlclient==2.0.1
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my57-py38-mysqlclient201:latest
+
+
+          # ==================================================================
+          # mysql-client 8 + Python 3.8
+          # ==================================================================
+          - ansible: stable-2.12
+            db_engine_version: mysql:8.0.31
+            python: '3.8'
+            connector: pymysql==0.9.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py38-pymysql093:latest
+          - ansible: stable-2.12
+            db_engine_version: mysql:8.0.31
+            python: '3.8'
+            connector: mysqlclient==2.0.1
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py38-mysqlclient201:latest
+
+
+          # ==================================================================
+          # mysql-client 8 + Python 3.9
+          # ==================================================================
+          - ansible: stable-2.13
+            db_engine_version: mysql:8.0.31
+            python: '3.9'
+            connector: pymysql==0.9.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py39-pymysql093:latest
+          - ansible: stable-2.13
+            db_engine_version: mysql:8.0.31
+            python: '3.9'
+            connector: mysqlclient==2.0.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py39-mysqlclient203:latest
+
+          - ansible: stable-2.14
+            db_engine_version: mysql:8.0.31
+            python: '3.9'
+            connector: pymysql==0.9.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py39-pymysql093:latest
+          - ansible: stable-2.14
+            db_engine_version: mysql:8.0.31
+            python: '3.9'
+            connector: mysqlclient==2.0.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py39-mysqlclient203:latest
+
+
+          # ==================================================================
+          # mysql-client 8 + Python 3.10
+          # ==================================================================
+          # - ansible: stable-2.13
+          #   db_engine_version: mysql:8.0.31
+          #   python: '3.10'
+          #   connector: pymysql==1.0.2
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py310-pymysql102:latest
+          - ansible: stable-2.13
+            db_engine_version: mysql:8.0.31
+            python: '3.10'
+            connector: mysqlclient==2.1.1
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py310-mysqlclient211:latest
+
+          # - ansible: stable-2.14
+          #   db_engine_version: mysql:8.0.31
+          #   python: '3.10'
+          #   connector: pymysql==1.0.2
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py310-pymysql102:latest
+          - ansible: stable-2.14
+            db_engine_version: mysql:8.0.31
+            python: '3.10'
+            connector: mysqlclient==2.1.1
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py310-mysqlclient211:latest
+
+          # - ansible: devel
+          #   db_engine_version: mysql:8.0.31
+          #   python: '3.10'
+          #   connector: pymysql==1.0.2
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py310-pymysql102:latest
+          - ansible: devel
+            db_engine_version: mysql:8.0.31
+            python: '3.10'
+            connector: mysqlclient==2.1.1
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-my80-py310-mysqlclient211:latest
+
+          # ==================================================================
+          # mariadb-client 10.3 + Python 3.8
+          # ==================================================================
+          - ansible: stable-2.12
+            db_engine_version: mariadb:10.4.27
+            python: '3.8'
+            connector: pymysql==0.9.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py38-pymysql093:latest
+          - ansible: stable-2.12
+            db_engine_version: mariadb:10.4.27
+            python: '3.8'
+            connector: mysqlclient==2.0.1
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py38-mysqlclient201:latest
+          # - ansible: stable-2.12
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.8'
+          #   connector: pymysql==0.9.3
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py38-pymysql093:latest
+          # - ansible: stable-2.12
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.8'
+          #   connector: mysqlclient==2.0.1
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py38-mysqlclient201:latest
+
+
+          # ==================================================================
+          # mariadb-client 10.3 + Python 3.9
+          # ==================================================================
+          - ansible: stable-2.13
+            db_engine_version: mariadb:10.4.27
+            python: '3.9'
+            connector: pymysql==0.9.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py39-pymysql093:latest
+          - ansible: stable-2.13
+            db_engine_version: mariadb:10.4.27
+            python: '3.9'
+            connector: mysqlclient==2.0.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py39-mysqlclient203:latest
+          # - ansible: stable-2.13
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.9'
+          #   connector: pymysql==0.9.3
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py39-pymysql093:latest
+          # - ansible: stable-2.13
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.9'
+          #   connector: mysqlclient==2.0.3
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py39-mysqlclient203:latest
+
+          - ansible: stable-2.14
+            db_engine_version: mariadb:10.4.27
+            python: '3.9'
+            connector: pymysql==0.9.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py39-pymysql093:latest
+          - ansible: stable-2.14
+            db_engine_version: mariadb:10.4.27
+            python: '3.9'
+            connector: mysqlclient==2.0.3
+            docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py39-mysqlclient203:latest
+          # - ansible: stable-2.14
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.9'
+          #   connector: pymysql==0.9.3
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py39-pymysql093:latest
+          # - ansible: stable-2.14
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.9'
+          #   connector: mysqlclient==2.0.3
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb103-py39-mysqlclient203:latest
+
+
+          # ==================================================================
+          # mariadb-client 10.6 + Python 3.10
+          # ==================================================================
+          # - ansible: stable-2.13
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.10'
+          #   connector: pymysql==1.0.2
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-pymysql102:latest
+          # - ansible: stable-2.13
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.10'
+          #   connector: mysqlclient==2.1.1
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-mysqlclient211:latest
+          # - ansible: stable-2.13
+          #   db_engine_version: mariadb:10.6.11
+          #   python: '3.10'
+          #   connector: pymysql==1.0.2
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-pymysql102:latest
+          # - ansible: stable-2.13
+          #   db_engine_version: mariadb:10.6.11
+          #   python: '3.10'
+          #   connector: mysqlclient==2.1.1
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-mysqlclient211:latest
+
+          # - ansible: stable-2.14
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.10'
+          #   connector: pymysql==1.0.2
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-pymysql102:latest
+          # - ansible: stable-2.14
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.10'
+          #   connector: mysqlclient==2.1.1
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-mysqlclient211:latest
+          # - ansible: stable-2.14
+          #   db_engine_version: mariadb:10.6.11
+          #   python: '3.10'
+          #   connector: pymysql==1.0.2
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-pymysql102:latest
+          # - ansible: stable-2.14
+          #   db_engine_version: mariadb:10.6.11
+          #   python: '3.10'
+          #   connector: mysqlclient==2.1.1
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-mysqlclient211:latest
+
+          # - ansible: devel
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.10'
+          #   connector: pymysql==1.0.2
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-pymysql102:latest
+          # - ansible: devel
+          #   db_engine_version: mariadb:10.5.18
+          #   python: '3.10'
+          #   connector: mysqlclient==2.1.1
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-mysqlclient211:latest
+          # - ansible: devel
+          #   db_engine_version: mariadb:10.6.11
+          #   python: '3.10'
+          #   connector: pymysql==1.0.2
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-pymysql102:latest
+          # - ansible: devel
+          #   db_engine_version: mariadb:10.6.11
+          #   python: '3.10'
+          #   connector: mysqlclient==2.1.1
+          #   docker_image: ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-mysqlclient211:latest
+
+    services:
+      db_primary:
+        image: docker.io/library/${{ matrix.db_engine_version }}
+        env:
+          MARIADB_ROOT_PASSWORD: msandbox
+          MYSQL_ROOT_PASSWORD: msandbox
+        ports:
+          - 3307:3306
+        # We write our own health-cmd because the mariadb container does not
+        # provide a healthcheck
+        options: >-
+          --health-cmd "mysqladmin ping -P 3306 -pmsandbox |grep alive || exit 1"
+          --health-start-period 10s
+          --health-interval 10s
+          --health-timeout 5s
+          --health-retries 6
+
+      db_replica1:
+        image: docker.io/library/${{ matrix.db_engine_version }}
+        env:
+          MARIADB_ROOT_PASSWORD: msandbox
+          MYSQL_ROOT_PASSWORD: msandbox
+        ports:
+          - 3308:3306
+        options: >-
+          --health-cmd "mysqladmin ping -P 3306 -pmsandbox |grep alive || exit 1"
+          --health-start-period 10s
+          --health-interval 10s
+          --health-timeout 5s
+          --health-retries 6
+
+      db_replica2:
+        image: docker.io/library/${{ matrix.db_engine_version }}
+        env:
+          MARIADB_ROOT_PASSWORD: msandbox
+          MYSQL_ROOT_PASSWORD: msandbox
+        ports:
+          - 3309:3306
+        options: >-
+          --health-cmd "mysqladmin ping -P 3306 -pmsandbox |grep alive || exit 1"
+          --health-start-period 10s
+          --health-interval 10s
+          --health-timeout 5s
+          --health-retries 6
+
     steps:
+
+      # No need to check for service health. GitHub Action took care of it.
+
+      - name: Restart MySQL server with settings for replication
+        run: |
+          docker exec ${{ job.services.db_primary.id }} bash -c 'echo -e [mysqld]\\nserver-id=1\\nlog-bin=/var/lib/mysql/primary-bin > /etc/mysql/conf.d/replication.cnf'
+          docker exec ${{ job.services.db_replica1.id }} bash -c 'echo -e [mysqld]\\nserver-id=2\\nlog-bin=/var/lib/mysql/replica1-bin > /etc/mysql/conf.d/replication.cnf'
+          docker exec ${{ job.services.db_replica2.id }} bash -c 'echo -e [mysqld]\\nserver-id=3\\nlog-bin=/var/lib/mysql/replica2-bin > /etc/mysql/conf.d/replication.cnf'
+          docker restart -t 30 ${{ job.services.db_primary.id }}
+          docker restart -t 30 ${{ job.services.db_replica1.id }}
+          docker restart -t 30 ${{ job.services.db_replica2.id }}
+
+      - name: Wait for the primary to be healthy
+        run: |
+          while ! /usr/bin/docker inspect --format="{{if .Config.Healthcheck}}{{print .State.Health.Status}}{{end}}" ${{ job.services.db_primary.id }} | grep healthy && [[ "$SECONDS" -lt 120 ]]; do sleep 1; done
+
       - name: >-
           Perform integration testing against
           Ansible version ${{ matrix.ansible }}
@@ -87,22 +354,17 @@ jobs:
         with:
           ansible-core-version: ${{ matrix.ansible }}
           pre-test-cmd: >-
-            DB_ENGINE=$(echo '${{ matrix.db_engine_version }}' | awk -F_ '{print $1}');
-            DB_VERSION=$(echo '${{ matrix.db_engine_version }}' | awk -F_ '{print $2}');
-            DB_ENGINE_PRETTY=$([[ "${DB_ENGINE}" == 'mysql' ]] && echo 'MySQL' || echo 'MariaDB');
-            >&2 echo Matrix factor for the DB is ${{ matrix.db_engine_version }}...;
-            >&2 echo Setting ${DB_ENGINE_PRETTY} version to ${DB_VERSION}...;
-            sed -i -e "s/^${DB_ENGINE}_version:.*/${DB_ENGINE}_version: $DB_VERSION/g" '${{ env.mysql_version_file }}';
-            if [[ ${{ matrix.db_engine_version }} == mariadb* ]];
-            then
-              echo Set MariaDB install flag...; sed -i -e "s/^mariadb_install: false/mariadb_install: true/g" '${{ env.mysql_version_file }}';
-              echo Set MariaDB v10.8.3 URL sub dir...; sed -i -e "s/^mariadb_url_subdir:.*/mariadb_url_subdir: linux-systemd/g" '${{ env.connector_version_file }}';
-            fi;
-            >&2 echo Setting Connector version to ${{ matrix.connector }}...;
-            sed -i 's/^python_packages:.*/python_packages: [${{ matrix.connector }}]/' ${{ env.connector_version_file }}
+              echo Setting db_engine_version to "${{ matrix.db_engine_version }}"...;
+              echo -n "${{ matrix.db_engine_version }}" > tests/integration/db_engine_version;
+              echo Setting Connector version to "${{ matrix.connector }}"...;
+              echo -n "${{ matrix.connector }}" > tests/integration/connector;
+              echo Setting Python version to "${{ matrix.python }}"...;
+              echo -n "${{ matrix.python }}" > tests/integration/python;
+              echo Setting Ansible version to "${{ matrix.ansible }}"...;
+              echo -n "${{ matrix.ansible }}" > tests/integration/ansible
+          docker-image: ${{ matrix.docker_image }}
           target-python-version: ${{ matrix.python }}
           testing-type: integration
-          pull-request-change-detection: true
 
   units:
     runs-on: ubuntu-20.04
@@ -121,13 +383,13 @@ jobs:
           - 3.8
           - 3.9
         exclude:
-          - python: 3.8
+          - python: '3.8'
             ansible: stable-2.13
-          - python: 3.8
+          - python: '3.8'
             ansible: stable-2.14
-          - python: 3.8
+          - python: '3.8'
             ansible: devel
-          - python: 3.9
+          - python: '3.9'
             ansible: stable-2.12
 
     steps:
diff --git a/.github/workflows/ansible-test-roles.yml b/.github/workflows/ansible-test-roles.yml
index 4748b5a..13e7d41 100644
--- a/.github/workflows/ansible-test-roles.yml
+++ b/.github/workflows/ansible-test-roles.yml
@@ -1,3 +1,4 @@
+---
 name: Roles CI
 on:
   push:
diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml
new file mode 100644
index 0000000..fa10268
--- /dev/null
+++ b/.github/workflows/build-docker-image.yml
@@ -0,0 +1,67 @@
+---
+name: Build Docker Image for ansible-test
+
+on:
+  workflow_call:
+    inputs:
+      registry:
+        required: true
+        type: string
+      image_name:
+        required: true
+        type: string
+      context:
+        required: true
+        type: string
+
+jobs:
+
+  build:
+
+    runs-on: ubuntu-latest
+    permissions:
+      contents: read
+      packages: write
+
+    steps:
+      # Requirement to use 'context' in docker/build-push-action@v3
+      - name: Checkout repository
+        uses: actions/checkout@v3
+
+      # https://github.com/docker/login-action
+      - name: Log into registry ${{ inputs.registry }}
+        uses: docker/login-action@v2
+        with:
+          registry: ${{ inputs.registry }}
+          username: ${{ github.actor }}
+          password: ${{ secrets.GITHUB_TOKEN }}
+
+      # https://github.com/docker/metadata-action
+      - name: Extract Docker metadata (tags, labels)
+        id: meta
+        uses: docker/metadata-action@v4
+        with:
+          images:
+            "${{ inputs.registry }}\
+            /${{ github.repository }}\
+            /${{ inputs.image_name }}"
+          tags: latest
+
+      # Setting up Docker Buildx with docker-container driver is required
+      # at the moment to be able to use a subdirectory with Git context
+      #
+      # https://github.com/docker/setup-buildx-action
+      - name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v2
+
+      # https://github.com/docker/build-push-action
+      - name: Build and push Docker image with Buildx
+        id: build-and-push
+        uses: docker/build-push-action@v3
+        with:
+          context: ${{ inputs.context }}
+          push: true
+          tags: ${{ steps.meta.outputs.tags }}
+          labels: ${{ steps.meta.outputs.labels }}
+          cache-from: type=gha
+          cache-to: type=gha,mode=max
diff --git a/.github/workflows/docker-image-mariadb103-py38-mysqlclient201.yml b/.github/workflows/docker-image-mariadb103-py38-mysqlclient201.yml
new file mode 100644
index 0000000..3d90270
--- /dev/null
+++ b/.github/workflows/docker-image-mariadb103-py38-mysqlclient201.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI mariadb103-py38-mysqlclient201
+
+on:
+  push:
+    paths:
+      - 'test-containers/mariadb103-py38-mysqlclient201/**'
+      - '.github/workflows/docker-image-mariadb103-py38-mysqlclient201.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-mariadb103-py38-mysqlclient201
+      context: test-containers/mariadb103-py38-mysqlclient201
diff --git a/.github/workflows/docker-image-mariadb103-py38-pymysql093.yml b/.github/workflows/docker-image-mariadb103-py38-pymysql093.yml
new file mode 100644
index 0000000..1ca4600
--- /dev/null
+++ b/.github/workflows/docker-image-mariadb103-py38-pymysql093.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI mariadb103-py38-pymysql093
+
+on:
+  push:
+    paths:
+      - 'test-containers/mariadb103-py38-pymysql093/**'
+      - '.github/workflows/docker-image-mariadb103-py38-pymysql093.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-mariadb103-py38-pymysql093
+      context: test-containers/mariadb103-py38-pymysql093
diff --git a/.github/workflows/docker-image-mariadb103-py39-mysqlclient203.yml b/.github/workflows/docker-image-mariadb103-py39-mysqlclient203.yml
new file mode 100644
index 0000000..37e91ee
--- /dev/null
+++ b/.github/workflows/docker-image-mariadb103-py39-mysqlclient203.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI mariadb103-py39-mysqlclient203
+
+on:
+  push:
+    paths:
+      - 'test-containers/mariadb103-py39-mysqlclient203/**'
+      - '.github/workflows/docker-image-mariadb103-py39-mysqlclient203.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-mariadb103-py39-mysqlclient203
+      context: test-containers/mariadb103-py39-mysqlclient203
diff --git a/.github/workflows/docker-image-mariadb103-py39-pymysql093.yml b/.github/workflows/docker-image-mariadb103-py39-pymysql093.yml
new file mode 100644
index 0000000..30acfc1
--- /dev/null
+++ b/.github/workflows/docker-image-mariadb103-py39-pymysql093.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI mariadb103-py39-pymysql093
+
+on:
+  push:
+    paths:
+      - 'test-containers/mariadb103-py39-pymysql093/**'
+      - '.github/workflows/docker-image-mariadb103-py39-pymysql093.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-mariadb103-py39-pymysql093
+      context: test-containers/mariadb103-py39-pymysql093
diff --git a/.github/workflows/docker-image-mariadb106-py310-mysqlclient211.yml b/.github/workflows/docker-image-mariadb106-py310-mysqlclient211.yml
new file mode 100644
index 0000000..0fa7403
--- /dev/null
+++ b/.github/workflows/docker-image-mariadb106-py310-mysqlclient211.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI mariadb106-py310-mysqlclient211
+
+on:
+  push:
+    paths:
+      - 'test-containers/mariadb106-py310-mysqlclient211/**'
+      - '.github/workflows/docker-image-mariadb106-py310-mysqlclient211.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-mariadb106-py310-mysqlclient211
+      context: test-containers/mariadb106-py310-mysqlclient211
diff --git a/.github/workflows/docker-image-mariadb106-py310-pymysql102.yml b/.github/workflows/docker-image-mariadb106-py310-pymysql102.yml
new file mode 100644
index 0000000..adfe9e3
--- /dev/null
+++ b/.github/workflows/docker-image-mariadb106-py310-pymysql102.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI mariadb106-py310-pymysql102
+
+on:
+  push:
+    paths:
+      - 'test-containers/mariadb106-py310-pymysql102/**'
+      - '.github/workflows/docker-image-mariadb106-py310-pymysql102.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-mariadb106-py310-pymysql102
+      context: test-containers/mariadb106-py310-pymysql102
diff --git a/.github/workflows/docker-image-my57-py38-mysqlclient201.yml b/.github/workflows/docker-image-my57-py38-mysqlclient201.yml
new file mode 100644
index 0000000..2c18f63
--- /dev/null
+++ b/.github/workflows/docker-image-my57-py38-mysqlclient201.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI my57-py38-mysqlclient201
+
+on:
+  push:
+    paths:
+      - 'test-containers/my57-py38-mysqlclient201/**'
+      - '.github/workflows/docker-image-my57-py38-mysqlclient201.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-my57-py38-mysqlclient201
+      context: test-containers/my57-py38-mysqlclient201
diff --git a/.github/workflows/docker-image-my57-py38-pymysql0711.yml b/.github/workflows/docker-image-my57-py38-pymysql0711.yml
new file mode 100644
index 0000000..1568d22
--- /dev/null
+++ b/.github/workflows/docker-image-my57-py38-pymysql0711.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI my57-py38-pymysql0711
+
+on:
+  push:
+    paths:
+      - 'test-containers/my57-py38-pymysql0711/**'
+      - '.github/workflows/docker-image-my57-py38-pymysql0711.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-my57-py38-pymysql0711
+      context: test-containers/my57-py38-pymysql0711
diff --git a/.github/workflows/docker-image-my57-py38-pymysql093.yml b/.github/workflows/docker-image-my57-py38-pymysql093.yml
new file mode 100644
index 0000000..39bb583
--- /dev/null
+++ b/.github/workflows/docker-image-my57-py38-pymysql093.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI my57-py38-pymysql093
+
+on:
+  push:
+    paths:
+      - 'test-containers/my57-py38-pymysql093/**'
+      - '.github/workflows/docker-image-my57-py38-pymysql093.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-my57-py38-pymysql093
+      context: test-containers/my57-py38-pymysql093
diff --git a/.github/workflows/docker-image-my80-py310-mysqlclient211.yml b/.github/workflows/docker-image-my80-py310-mysqlclient211.yml
new file mode 100644
index 0000000..824f77c
--- /dev/null
+++ b/.github/workflows/docker-image-my80-py310-mysqlclient211.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI my80-py310-mysqlclient211
+
+on:
+  push:
+    paths:
+      - 'test-containers/my80-py310-mysqlclient211/**'
+      - '.github/workflows/docker-image-my80-py310-mysqlclient211.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-my80-py310-mysqlclient211
+      context: test-containers/my80-py310-mysqlclient211
diff --git a/.github/workflows/docker-image-my80-py310-pymysql102.yml b/.github/workflows/docker-image-my80-py310-pymysql102.yml
new file mode 100644
index 0000000..0c54e12
--- /dev/null
+++ b/.github/workflows/docker-image-my80-py310-pymysql102.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI my80-py310-pymysql102
+
+on:
+  push:
+    paths:
+      - 'test-containers/my80-py310-pymysql102/**'
+      - '.github/workflows/docker-image-my80-py310-pymysql102.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-my80-py310-pymysql102
+      context: test-containers/my80-py310-pymysql102
diff --git a/.github/workflows/docker-image-my80-py38-mysqlclient201.yml b/.github/workflows/docker-image-my80-py38-mysqlclient201.yml
new file mode 100644
index 0000000..0ac76b2
--- /dev/null
+++ b/.github/workflows/docker-image-my80-py38-mysqlclient201.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI my80-py38-mysqlclient201
+
+on:
+  push:
+    paths:
+      - 'test-containers/my80-py38-mysqlclient201/**'
+      - '.github/workflows/docker-image-my80-py38-mysqlclient201.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-my80-py38-mysqlclient201
+      context: test-containers/my80-py38-mysqlclient201
diff --git a/.github/workflows/docker-image-my80-py38-pymysql093.yml b/.github/workflows/docker-image-my80-py38-pymysql093.yml
new file mode 100644
index 0000000..1677be6
--- /dev/null
+++ b/.github/workflows/docker-image-my80-py38-pymysql093.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI my80-py38-pymysql093
+
+on:
+  push:
+    paths:
+      - 'test-containers/my80-py38-pymysql093/**'
+      - '.github/workflows/docker-image-my80-py38-pymysql093.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-my80-py38-pymysql093
+      context: test-containers/my80-py38-pymysql093
diff --git a/.github/workflows/docker-image-my80-py39-mysqlclient203.yml b/.github/workflows/docker-image-my80-py39-mysqlclient203.yml
new file mode 100644
index 0000000..e6b41db
--- /dev/null
+++ b/.github/workflows/docker-image-my80-py39-mysqlclient203.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI my80-py39-mysqlclient203
+
+on:
+  push:
+    paths:
+      - 'test-containers/my80-py39-mysqlclient203/**'
+      - '.github/workflows/docker-image-my80-py39-mysqlclient203.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-my80-py39-mysqlclient203
+      context: test-containers/my80-py39-mysqlclient203
diff --git a/.github/workflows/docker-image-my80-py39-pymysql093.yml b/.github/workflows/docker-image-my80-py39-pymysql093.yml
new file mode 100644
index 0000000..72ffd60
--- /dev/null
+++ b/.github/workflows/docker-image-my80-py39-pymysql093.yml
@@ -0,0 +1,19 @@
+---
+name: Docker Image CI my80-py39-pymysql093
+
+on:
+  push:
+    paths:
+      - 'test-containers/my80-py39-pymysql093/*'
+      - '.github/workflows/docker-image-my80-py39-pymysql093.yml'
+      - '.github/workflows/build-docker-image.yml'
+
+jobs:
+
+  call-workflow-passing-data:
+    uses: ./.github/workflows/build-docker-image.yml
+    secrets: inherit
+    with:
+      registry: ghcr.io
+      image_name: test-container-my80-py39-pymysql093
+      context: test-containers/my80-py39-pymysql093
diff --git a/.gitignore b/.gitignore
index 1922df0..9555f5e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 /tests/output/
+/tests/integration/inventory
 /changelogs/.plugin-cache.yaml
 *.swp
 
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a94ffd8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,80 @@
+SHELL := /bin/bash
+
+# To tell ansible-test and Make to not kill the containers on failure or
+# end of tests. Disabled by default.
+ifdef keep_containers_alive
+	_keep_containers_alive = --docker-terminate never
+endif
+
+# This match what GitHub Action will do. Disabled by default.
+ifdef continue_on_errors
+	_continue_on_errors = --retry-on-error --continue-on-error
+endif
+
+.PHONY: test-integration
+test-integration:
+	echo -n $(db_engine_version) > tests/integration/db_engine_version
+	echo -n $(connector) > tests/integration/connector
+	echo -n $(python) > tests/integration/python
+	echo -n $(ansible) > tests/integration/ansible
+	# Create podman network for systems missing it. Error can be ignored
+	podman network create podman || true
+	podman run \
+		--detach \
+		--replace \
+		--name primary \
+		--env MARIADB_ROOT_PASSWORD=msandbox \
+		--env MYSQL_ROOT_PASSWORD=msandbox \
+		--network podman \
+		--publish 3307:3306 \
+		--health-cmd 'mysqladmin ping -P 3306 -pmsandbox | grep alive || exit 1' \
+		docker.io/library/$(db_engine_version) \
+		mysqld
+	podman run \
+		--detach \
+		--replace \
+		--name replica1 \
+		--env MARIADB_ROOT_PASSWORD=msandbox \
+		--env MYSQL_ROOT_PASSWORD=msandbox \
+		--network podman \
+		--publish 3308:3306 \
+		--health-cmd 'mysqladmin ping -P 3306 -pmsandbox | grep alive || exit 1' \
+		docker.io/library/$(db_engine_version) \
+		mysqld
+	podman run \
+		--detach \
+		--replace \
+		--name replica2 \
+		--env MARIADB_ROOT_PASSWORD=msandbox \
+		--env MYSQL_ROOT_PASSWORD=msandbox \
+		--network podman \
+		--publish 3309:3306 \
+		--health-cmd 'mysqladmin ping -P 3306 -pmsandbox | grep alive || exit 1' \
+		docker.io/library/$(db_engine_version) \
+		mysqld
+	# Setup replication and restart containers
+	podman exec primary bash -c 'echo -e [mysqld]\\nserver-id=1\\nlog-bin=/var/lib/mysql/primary-bin > /etc/mysql/conf.d/replication.cnf'
+	podman exec replica1 bash -c 'echo -e [mysqld]\\nserver-id=2\\nlog-bin=/var/lib/mysql/replica1-bin > /etc/mysql/conf.d/replication.cnf'
+	podman exec replica2 bash -c 'echo -e [mysqld]\\nserver-id=3\\nlog-bin=/var/lib/mysql/replica2-bin > /etc/mysql/conf.d/replication.cnf'
+	# Don't restart a container unless it is healthy
+	while ! podman healthcheck run primary && [[ "$$SECONDS" -lt 120 ]]; do sleep 1; done
+	podman restart -t 30 primary
+	while ! podman healthcheck run replica1 && [[ "$$SECONDS" -lt 120 ]]; do sleep 1; done
+	podman restart -t 30 replica1
+	while ! podman healthcheck run replica2 && [[ "$$SECONDS" -lt 120 ]]; do sleep 1; done
+	podman restart -t 30 replica2
+	while ! podman healthcheck run primary && [[ "$$SECONDS" -lt 120 ]]; do sleep 1; done
+	mkdir -p .venv/$(ansible)
+	python$(local_python_version) -m venv .venv/$(ansible)
+	source .venv/$(ansible)/bin/activate
+	python$(local_python_version) -m ensurepip
+	python$(local_python_version) -m pip install --disable-pip-version-check https://github.com/ansible/ansible/archive/$(ansible).tar.gz
+	-set -x; ansible-test integration $(target) -v --color --coverage --diff --docker $(docker_image) --docker-network podman $(_continue_on_errors) $(_keep_containers_alive) --python $(python); set +x
+	rm tests/integration/db_engine_version
+	rm tests/integration/connector
+	rm tests/integration/python
+	rm tests/integration/ansible
+ifndef keep_containers_alive
+	podman stop --time 0 --ignore primary replica1 replica2
+	podman rm --ignore --volumes primary replica1 replica2
+endif
diff --git a/README.md b/README.md
index ac6eaea..09a88d8 100644
--- a/README.md
+++ b/README.md
@@ -62,23 +62,32 @@ Every voice is important and every idea is valuable. If you have something on yo
 
 ### ansible-core
 
-- 2.11
 - 2.12
 - 2.13
+- 2.14
 - current development version
 
 ### Databases
 
-- mysql 5.7.31
-- mysql 8.0.22
-- mariadb 10.3.34 (only collection version >= 3)
-- mariadb 10.8.3 (only collection version >= 3)
+For MariaDB, only Long Term releases are tested.
+
+- mysql 5.7.40
+- mysql 8.0.31
+- mariadb:10.3.34 (only collection version <= 3.5.1)
+- mariadb:10.4.24 (only collection version >= 3.5.2)
+- mariadb:10.5.18 (only collection version >= 3.5.2)
+- mariadb:10.6.11 (only collection version >= 3.5.2)
+- mariadb:10.11.?? (waiting for release)
+
 
 ### Database connectors
 
-- pymysql 0.7.10
+- pymysql 0.7.11 (Only tested with MySQL 5.7)
 - pymysql 0.9.3
+- pymysql 1.0.2 (only collection version >= ???) !!! Unsuported until future release !!!
 - mysqlclient 2.0.1
+- mysqlclient 2.0.3 (only collection version >= 3.5.2)
+- mysqlclient 2.1.1 (only collection version >= 3.5.2)
 
 ## External requirements
 
diff --git a/TESTING.md b/TESTING.md
new file mode 100644
index 0000000..9aad0f5
--- /dev/null
+++ b/TESTING.md
@@ -0,0 +1,87 @@
+# Tests
+
+This collection uses GitHub Actions to run ansible-test to validate its content. Three type of tests are used: Sanity, Integration and Units.
+
+The tests covers the code for plugins and roles (no role available yet, but tests are ready) and can be found here:
+
+- Plugins: *.github/workflows/ansible-test-plugins.yml*
+- Roles: *.github/workflows/ansible-test-roles.yml* (unused yet)
+
+Everytime you push on your fork or you create a pull request, both workflows runs. You can see the output on the "Actions" tab.
+
+
+## Integration tests
+
+You can use GitHub to run ansible-test either on the community repo or your fork. But sometimes you want to quickly test a single version or a single target. To do that, you can use the Makefile present at the root of this repository.
+
+For now, the makefile only supports Podman.
+
+### Requirements
+
+- python >= 3.8 and <= 3.10
+- make
+- Minimum 15GB of free space on the device storing containers images and volumes. You can use this command to check: `podman system info --format='{{.Store.GraphRoot}}'|xargs findmnt --noheadings --nofsroot --output SOURCE --target|xargs df -h --output=size,used,avail,pcent,target`
+- Minimum 2GB of RAM
+
+
+### Makefile options
+
+The Makefile accept the following options:
+
+- **local_python_version**: This option can be omitted if your system has a version supported by Ansible. You can check with `python -V`.
+- **ansible**: Mandatory version of ansible to install in a venv to run ansible-test.
+- **docker_image**:
+    The container image to use to run our tests. Those images Dockerfile are in https://github.com/community.mysql/test-containers and then pushed to quay.io: E.G.:
+    `quay.io/mws/community-mysql-test-containers-my57-py38-mysqlclient201-pymysql0711:latest`. Look in the link above for a complete list of available containers. You can also look into `.github/workflows/ansible-test-plugins.yml`
+    Unfortunatly you must provide the right container_image yourself. And you still need to provides db_engine_version, python, etc... because ansible-test won't do black magic to try to detect what we expect. Explicit is better than implicit anyway.
+    To minimise the amount of images, pymysql 0.7.11 and mysqlclient are shipped together.
+- **db_engine_version**: The name of the container to use for the service containers that will host a primary database and two replicas. Either MYSQL or MariaDB. Use ':' as a separator. Do not use short version, like mysql:8 for instance. Our tests expect a full version to filter tests precisely. For instance: `when: db_version is version ('8.0.22', '>')`.
+- **connector**: The name of the python package of the connector along with its version number. Use '==' as a separator.
+- **python**: The python version to use in the controller.
+- **target** : If omitted, all test targets will run. But you can limit the tests to a single target to speed up your tests.
+- **keep_containers_alive**: This option keeps all tree databases containers and the ansible-test container alive at the end of tests or in case of failure. This is useful to enter one of the containers with `podman exec -it <container-name> bash` for debugging. Rerunning the
+test will recreate those containers.
+- **continue_on_errors**: Tells ansible-test to retry on errors and also continue on errors. This is the way the GitHub Action's workflow runs the tests. If you develop a new target, this option can be used to validate that your tests cleanup everything so a new run can restart without errors like "Failed to create database x because it already exists".
+
+Examples:
+
+```sh
+# Run all targets
+make ansible="stable-2.12" db_engine_version="mysql:5.7.40" python="3.8" connector="pymysql==0.7.11" docker_image="ghcr.io/community.mysql/test-container-my57-py38-pymysql0711:latest"
+
+# A single target
+make ansible="stable-2.14" db_engine_version="mysql:5.7.40" python="3.8" connector="pymysql==0.7.11" docker_image="ghcr.io/community.mysql/test-container-my57-py38-pymysql0711:latest" target="test_mysql_db"
+
+# Keep databases and ansible tests containers alives
+# A single target and continue on errors
+make ansible="stable-2.14" db_engine_version="mysql:8.0.31" python="3.9" connector="mysqlclient==2.0.3" docker_image="ghcr.io/community.mysql/test-container-my80-py39-mysqlclient203:latest" target="test_mysql_db" keep_containers_alive=1 continue_on_errors=1
+
+# If your system has an usupported version of Python:
+make local_python_version="3.8" ansible="stable-2.14" db_engine_version="mariadb:10.6.11" python="3.9" connector="pymysql==0.9.3" docker_image="ghcr.io/community.mysql/test-container-mariadb103-py39-pymysql093:latest"
+```
+
+
+### Run all tests
+
+GitHub Action offer a test matrix that run every combination of Python, MySQL, MariaDB and Connector against each other. To reproduce this, this repo provides a script called *run_all_tests.py*.
+
+Examples:
+
+```sh
+python run_all_tests.py
+```
+
+
+### Add a new Python, Connector or Database version
+
+1. Add a workflow in [.github/workflows/](.github/workflows)
+1. Add a new folder in [test-containers](test-containers) containing a new Dockerfile. Your container must contains 3 things:
+  - The python interpreter
+  - The python package to connect to the database (pymysql, mysqlclient, ...)
+  - A mysql client to query the database before to prepare tests before our tests starts. This client must provide both `mysql` and `mysqldump` commands.
+1. Add your version in *.github/workflows/ansible-test-plugins.yml*
+
+After pushing the commit to the remote, the container will be build and published on ghcr.io. Have a look in the "Action" tab to see if it worked. In case of error `failed to copy: io: read/write on closed pipe` re-run the workflow, this append unfortunately a lot.
+
+To see the docker image produced, go to the main GitHub page of your fork or community.mysql (depending were you pushed) and look for the link "Packages" on the right hand side of the page. This page indicate a "Published x days ago" that is updated infrequently. To see the last time the container has been updated you must click on its title and look in the right hands side bellow the title "Last published".
+
diff --git a/changelogs/fragments/490_refactor_integration_tests.yml b/changelogs/fragments/490_refactor_integration_tests.yml
new file mode 100644
index 0000000..0762adf
--- /dev/null
+++ b/changelogs/fragments/490_refactor_integration_tests.yml
@@ -0,0 +1,6 @@
+---
+minor_changes:
+  - Integration tests - Add more versions of MariaDB
+  - Integration tests - Carefully verify every component of the tests in the new target 'setup_controller' to ensure expected versions are correct Python, Ansible, connector and MySQL/MariaDB.
+  - Integration tests - Add tools to test locally the same as on GHA by using same containers and virtualenv. Custom test containers are published in ghcr.io by this repo's workflows. MySQL/MariaDB are official Docker Hub images.
+  - Integration tests - New name for many tasks to makes it easier to find failing tests. Rename duplicates. Add name for tasks which doesn't had one, refactor some tests files to better group tests by subject, ...
diff --git a/changelogs/fragments/backport-stable-1-pr-490.yml b/changelogs/fragments/backport-stable-1-pr-490.yml
new file mode 100644
index 0000000..5aab754
--- /dev/null
+++ b/changelogs/fragments/backport-stable-1-pr-490.yml
@@ -0,0 +1,3 @@
+---
+trivial:
+  - Integration tests - Backport PR490
diff --git a/run_all_tests.py b/run_all_tests.py
new file mode 100755
index 0000000..b7779a5
--- /dev/null
+++ b/run_all_tests.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+import yaml
+import os
+
+github_workflow_file = '.github/workflows/ansible-test-plugins.yml'
+
+
+def read_github_workflow_file():
+    with open(github_workflow_file, 'r') as gh_file:
+        try:
+            return yaml.safe_load(gh_file)
+        except yaml.YAMLError as exc:
+            print(exc)
+
+
+def extract_value(target, dict_yaml):
+    for key, value in dict_yaml.items():
+        if key == target:
+            return value
+
+
+def extract_matrix(workflow_yaml):
+    jobs = extract_value('jobs', workflow_yaml)
+    integration = extract_value('integration', jobs)
+    strategy = extract_value('strategy', integration)
+    matrix = extract_value('matrix', strategy)
+    return matrix
+
+
+# def is_exclude(exclude_list, test_suite):
+#     test_is_excluded = False
+#     for excl in exclude_list:
+#         match = 0
+
+#         if 'ansible' in excl:
+#             if excl.get('ansible') == test_suite[0]:
+#                 match += 1
+
+#         if 'db_engine_version' in excl:
+#             if excl.get('db_engine_version') == test_suite[1]:
+#                 match += 1
+
+#         if 'python' in excl:
+#             if excl.get('python') == test_suite[2]:
+#                 match += 1
+
+#         if 'connector' in excl:
+#             if excl.get('connector') == test_suite[3]:
+#                 match += 1
+
+#         if match > 1:
+#             test_is_excluded = True
+
+#     return test_is_excluded
+
+
+def main():
+    workflow_yaml = read_github_workflow_file()
+    tests_matrix_yaml = extract_matrix(workflow_yaml)
+
+    # matrix = []
+    # exclude_list = tests_matrix_yaml.get('exclude')
+    # for ansible in tests_matrix_yaml.get('ansible'):
+    #     for db_engine in tests_matrix_yaml.get('db_engine_version'):
+    #         for python in tests_matrix_yaml.get('python'):
+    #             for connector in tests_matrix_yaml.get('connector'):
+    #                 if not is_exclude(exclude_list, (ansible, db_engine, python, connector)):
+    #                     matrix.append((ansible, db_engine, python, connector))
+
+    for tests in tests_matrix_yaml.get('include'):
+        a = tests.get('ansible')
+        d = tests.get('db_engine_version')
+        p = tests.get('python')
+        c = tests.get('connector')
+        i = tests.get('docker_image')
+        make_cmd = f'make ansible="{a}" db_engine_version="{d}" python="{p}" connector="{c}" docker_image="{i}" test-integration'
+        print(f'Run tests for: Ansible: {a}, DB: {d}, Python: {p}, Connector: {c}, Docker image: {i}')
+        os.system(make_cmd)
+        # TODO, allow for CTRL+C to break the loop more easily
+        # TODO, store the failures from this iteration
+    # TODO, display a summary of failures from every iterations
+
+
+if __name__ == '__main__':
+    main()
diff --git a/test-containers/mariadb103-py38-mysqlclient201/Dockerfile b/test-containers/mariadb103-py38-mysqlclient201/Dockerfile
new file mode 100644
index 0000000..68ea3f6
--- /dev/null
+++ b/test-containers/mariadb103-py38-mysqlclient201/Dockerfile
@@ -0,0 +1,21 @@
+FROM quay.io/ansible/ubuntu2004-test-container:main
+# ubuntu2004 comes with mariadb-client-10.3
+
+# iproute2                     # To grab docker network gateway address
+# python3.8-dev                # Reqs for mysqlclient
+# default-libmysqlclient-dev   # Reqs for mysqlclient
+# build-essential              # Reqs for mysqlclient
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.8 \
+    python3.8-dev \
+    mariadb-client \
+    iproute2 \
+    default-libmysqlclient-dev \
+    build-essential
+
+RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.1 
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/mariadb103-py38-pymysql093/Dockerfile b/test-containers/mariadb103-py38-pymysql093/Dockerfile
new file mode 100644
index 0000000..22c8c57
--- /dev/null
+++ b/test-containers/mariadb103-py38-pymysql093/Dockerfile
@@ -0,0 +1,15 @@
+FROM quay.io/ansible/ubuntu2004-test-container:main
+# ubuntu2004 comes with mariadb-client-10.3
+
+# iproute2                     # To grab docker network gateway address
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.8 \
+    mariadb-client \
+    iproute2
+
+RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.9.3
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/mariadb103-py39-mysqlclient203/Dockerfile b/test-containers/mariadb103-py39-mysqlclient203/Dockerfile
new file mode 100644
index 0000000..b7837b2
--- /dev/null
+++ b/test-containers/mariadb103-py39-mysqlclient203/Dockerfile
@@ -0,0 +1,21 @@
+FROM quay.io/ansible/ubuntu2004-test-container:main
+# ubuntu2004 comes with mariadb-client-10.3
+
+# iproute2                     # To grab docker network gateway address
+# python3.9-dev                # Reqs for mysqlclient
+# default-libmysqlclient-dev   # Reqs for mysqlclient
+# build-essential              # Reqs for mysqlclient
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.9 \
+    python3.9-dev \
+    mariadb-client \
+    iproute2 \
+    default-libmysqlclient-dev \
+    build-essential
+
+RUN python3.9 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.3 
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/mariadb103-py39-pymysql093/Dockerfile b/test-containers/mariadb103-py39-pymysql093/Dockerfile
new file mode 100644
index 0000000..a1451ff
--- /dev/null
+++ b/test-containers/mariadb103-py39-pymysql093/Dockerfile
@@ -0,0 +1,15 @@
+FROM quay.io/ansible/ubuntu2004-test-container:main
+# ubuntu2004 comes with mariadb-client-10.3
+
+# iproute2                     # To grab docker network gateway address
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.9 \
+    mariadb-client \
+    iproute2
+
+RUN python3.9 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.9.3
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/mariadb106-py310-mysqlclient211/Dockerfile b/test-containers/mariadb106-py310-mysqlclient211/Dockerfile
new file mode 100644
index 0000000..f7e9eb1
--- /dev/null
+++ b/test-containers/mariadb106-py310-mysqlclient211/Dockerfile
@@ -0,0 +1,21 @@
+FROM quay.io/ansible/ubuntu2204-test-container:main
+# ubuntu2204 comes with mariadb-client-10.6
+
+# iproute2                     # To grab docker network gateway address
+# python3.10-dev               # Reqs for mysqlclient
+# default-libmysqlclient-dev   # Reqs for mysqlclient
+# build-essential              # Reqs for mysqlclient
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.10 \
+    python3.10-dev \
+    mariadb-client \
+    iproute2 \
+    default-libmysqlclient-dev \
+    build-essential
+
+RUN python3.10 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.1.1 
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/mariadb106-py310-pymysql102/Dockerfile b/test-containers/mariadb106-py310-pymysql102/Dockerfile
new file mode 100644
index 0000000..afe6a77
--- /dev/null
+++ b/test-containers/mariadb106-py310-pymysql102/Dockerfile
@@ -0,0 +1,15 @@
+FROM quay.io/ansible/ubuntu2204-test-container:main
+# ubuntu2204 comes with mariadb-client-10.6
+
+# iproute2                     # To grab docker network gateway address
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.10 \
+    mariadb-client \
+    iproute2
+
+RUN python3.10 -m pip install --disable-pip-version-check --no-cache-dir pymysql==1.0.2
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/my57-py38-mysqlclient201/Dockerfile b/test-containers/my57-py38-mysqlclient201/Dockerfile
new file mode 100644
index 0000000..0eb1778
--- /dev/null
+++ b/test-containers/my57-py38-mysqlclient201/Dockerfile
@@ -0,0 +1,21 @@
+FROM quay.io/ansible/ubuntu1804-test-container:main
+# ubuntu1804 comes with mysql-client-5.7
+
+# iproute2                     # To grab docker network gateway address
+# python3.8-dev                # Reqs for mysqlclient
+# default-libmysqlclient-dev   # Reqs for mysqlclient
+# build-essential              # Reqs for mysqlclient
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.8 \
+    python3.8-dev \
+    mysql-client \
+    iproute2 \
+    default-libmysqlclient-dev \
+    build-essential
+
+RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.1
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/my57-py38-pymysql0711/Dockerfile b/test-containers/my57-py38-pymysql0711/Dockerfile
new file mode 100644
index 0000000..9141709
--- /dev/null
+++ b/test-containers/my57-py38-pymysql0711/Dockerfile
@@ -0,0 +1,21 @@
+FROM quay.io/ansible/ubuntu1804-test-container:main
+# ubuntu1804 comes with mysql-client-5.7
+
+# iproute2                     # To grab docker network gateway address
+# python3.8-dev                # Reqs for mysqlclient
+# default-libmysqlclient-dev   # Reqs for mysqlclient
+# build-essential              # Reqs for mysqlclient
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.8 \
+    python3.8-dev \
+    mysql-client \
+    iproute2 \
+    default-libmysqlclient-dev \
+    build-essential
+
+RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.7.11
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/my57-py38-pymysql093/Dockerfile b/test-containers/my57-py38-pymysql093/Dockerfile
new file mode 100644
index 0000000..6b0f519
--- /dev/null
+++ b/test-containers/my57-py38-pymysql093/Dockerfile
@@ -0,0 +1,15 @@
+FROM quay.io/ansible/ubuntu1804-test-container:main
+# ubuntu1804 comes with mysql-client-5.7
+
+# iproute2  # To grab docker network gateway address
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.8 \
+    mysql-client \
+    iproute2
+
+RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.9.3
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/my80-py310-mysqlclient211/Dockerfile b/test-containers/my80-py310-mysqlclient211/Dockerfile
new file mode 100644
index 0000000..1aea0cd
--- /dev/null
+++ b/test-containers/my80-py310-mysqlclient211/Dockerfile
@@ -0,0 +1,21 @@
+FROM quay.io/ansible/ubuntu2204-test-container:main
+# ubuntu2204 comes with mysql-client-8
+
+# iproute2  # To grab docker network gateway address
+# python3.10-dev               # Reqs for mysqlclient
+# default-libmysqlclient-dev   # Reqs for mysqlclient
+# build-essential              # Reqs for mysqlclient
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.10 \
+    python3.10-dev \
+    mysql-client \
+    iproute2 \
+    default-libmysqlclient-dev \
+    build-essential
+
+RUN python3.10 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.1.1
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/my80-py310-pymysql102/Dockerfile b/test-containers/my80-py310-pymysql102/Dockerfile
new file mode 100644
index 0000000..871a1e4
--- /dev/null
+++ b/test-containers/my80-py310-pymysql102/Dockerfile
@@ -0,0 +1,15 @@
+FROM quay.io/ansible/ubuntu2204-test-container:main
+# ubuntu2204 comes with mysql-client-8
+
+# iproute2  # To grab docker network gateway address
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.10 \
+    mysql-client \
+    iproute2
+
+RUN python3.10 -m pip install --disable-pip-version-check --no-cache-dir pymysql==1.0.2
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/my80-py38-mysqlclient201/Dockerfile b/test-containers/my80-py38-mysqlclient201/Dockerfile
new file mode 100644
index 0000000..eb835c2
--- /dev/null
+++ b/test-containers/my80-py38-mysqlclient201/Dockerfile
@@ -0,0 +1,21 @@
+FROM quay.io/ansible/ubuntu2004-test-container:main
+# ubuntu2004 comes with mysql-client-8
+
+# iproute2  # To grab docker network gateway address
+# python3.8-dev                # Reqs for mysqlclient
+# default-libmysqlclient-dev   # Reqs for mysqlclient
+# build-essential              # Reqs for mysqlclient
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.8 \
+    python3.8-dev \
+    mysql-client \
+    iproute2 \
+    default-libmysqlclient-dev \
+    build-essential
+
+RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.1
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/my80-py38-pymysql093/Dockerfile b/test-containers/my80-py38-pymysql093/Dockerfile
new file mode 100644
index 0000000..e97e5e2
--- /dev/null
+++ b/test-containers/my80-py38-pymysql093/Dockerfile
@@ -0,0 +1,15 @@
+FROM quay.io/ansible/ubuntu2004-test-container:main
+# ubuntu2004 comes with mysql-client-8
+
+# iproute2  # To grab docker network gateway address
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.8 \
+    mysql-client \
+    iproute2
+
+RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.9.3
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/my80-py39-mysqlclient203/Dockerfile b/test-containers/my80-py39-mysqlclient203/Dockerfile
new file mode 100644
index 0000000..396d895
--- /dev/null
+++ b/test-containers/my80-py39-mysqlclient203/Dockerfile
@@ -0,0 +1,21 @@
+FROM quay.io/ansible/ubuntu2004-test-container:main
+# ubuntu2004 comes with mysql-client-8
+
+# iproute2  # To grab docker network gateway address
+# python3.9-dev                # Reqs for mysqlclient
+# default-libmysqlclient-dev   # Reqs for mysqlclient
+# build-essential              # Reqs for mysqlclient
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.9 \
+    python3.9-dev \
+    mysql-client \
+    iproute2 \
+    default-libmysqlclient-dev \
+    build-essential
+
+RUN python3.9 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.3
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/test-containers/my80-py39-pymysql093/Dockerfile b/test-containers/my80-py39-pymysql093/Dockerfile
new file mode 100644
index 0000000..57ef15e
--- /dev/null
+++ b/test-containers/my80-py39-pymysql093/Dockerfile
@@ -0,0 +1,16 @@
+FROM quay.io/ansible/ubuntu2004-test-container:main
+# ubuntu2004 comes with mysql-client-8
+
+# iproute2  # To grab docker network gateway address
+RUN apt-get update -y && \
+    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+    python3.9 \
+    mysql-client \
+    iproute2
+
+# cffi      # To connect to MySQL 8 with Python3.9 and PyMySQL
+RUN python3.9 -m pip install --disable-pip-version-check --no-cache-dir cffi pymysql==0.9.3
+
+ENV container=docker
+CMD ["/sbin/init"]
diff --git a/tests/integration/old_mariadb_replication/defaults/main.yml b/tests/integration/old_mariadb_replication/defaults/main.yml
index 3751f4e..eb32dc1 100644
--- a/tests/integration/old_mariadb_replication/defaults/main.yml
+++ b/tests/integration/old_mariadb_replication/defaults/main.yml
@@ -1,3 +1,5 @@
+---
+mysql_host: "{{ gateway_addr }}"
 master_port: 3306
 standby_port: 3307
 test_db: test_db
diff --git a/tests/integration/old_mariadb_replication/tasks/mariadb_master_use_gtid.yml b/tests/integration/old_mariadb_replication/tasks/mariadb_master_use_gtid.yml
index e3e7605..699b61f 100644
--- a/tests/integration/old_mariadb_replication/tasks/mariadb_master_use_gtid.yml
+++ b/tests/integration/old_mariadb_replication/tasks/mariadb_master_use_gtid.yml
@@ -11,7 +11,7 @@
 # Auxiliary step:
 - name: Get master status
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ primary_db.port }}"
     mode: getmaster
   register: primary_status
@@ -19,10 +19,10 @@
 # Set master_use_gtid disabled:
 - name: Run replication
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: changemaster
-    master_host: 127.0.0.1
+    master_host: '{{ mysql_host }}'
     master_port: "{{ primary_db.port }}"
     master_user: "{{ replication_user }}"
     master_password: "{{ replication_pass }}"
@@ -38,13 +38,13 @@
 # Start standby for further tests:
 - name: Start standby
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ primary_db.port }}"
     mode: startslave
 
 - name: Get standby status
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: getslave
   register: slave_status
@@ -56,7 +56,7 @@
 # Stop standby for further tests:
 - name: Stop standby
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: stopslave
 
@@ -67,7 +67,7 @@
 # Auxiliary step:
 - name: Get master status
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ primary_db.port }}"
     mode: getmaster
   register: primary_status
@@ -75,10 +75,10 @@
 # Set master_use_gtid current_pos:
 - name: Run replication
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: changemaster
-    master_host: 127.0.0.1
+    master_host: '{{ mysql_host }}'
     master_port: "{{ primary_db.port }}"
     master_user: "{{ replication_user }}"
     master_password: "{{ replication_pass }}"
@@ -94,13 +94,13 @@
 # Start standby for further tests:
 - name: Start standby
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ primary_db.port }}"
     mode: startslave
 
 - name: Get standby status
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: getslave
   register: slave_status
@@ -112,7 +112,7 @@
 # Stop standby for further tests:
 - name: Stop standby
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: stopslave
 
@@ -123,7 +123,7 @@
 # Auxiliary step:
 - name: Get master status
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ primary_db.port }}"
     mode: getmaster
   register: primary_status
@@ -131,10 +131,10 @@
 # Set master_use_gtid slave_pos:
 - name: Run replication
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: changemaster
-    master_host: 127.0.0.1
+    master_host: '{{ mysql_host }}'
     master_port: "{{ primary_db.port }}"
     master_user: "{{ replication_user }}"
     master_password: "{{ replication_pass }}"
@@ -150,13 +150,13 @@
 # Start standby for further tests:
 - name: Start standby
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ primary_db.port }}"
     mode: startslave
 
 - name: Get standby status
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: getslave
   register: slave_status
@@ -168,6 +168,6 @@
 # Stop standby for further tests:
 - name: Stop standby
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: stopslave
diff --git a/tests/integration/old_mariadb_replication/tasks/mariadb_replication_connection_name.yml b/tests/integration/old_mariadb_replication/tasks/mariadb_replication_connection_name.yml
index 98fa5fe..3928c78 100644
--- a/tests/integration/old_mariadb_replication/tasks/mariadb_replication_connection_name.yml
+++ b/tests/integration/old_mariadb_replication/tasks/mariadb_replication_connection_name.yml
@@ -4,20 +4,20 @@
 # Needs for further tests:
 - name: Stop slave
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: stopslave
 
 - name: Reset slave all
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: resetslaveall
 
 # Get master log pos:
 - name: Get master status
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ primary_db.port }}"
     mode: getmaster
   register: primary_status
@@ -25,10 +25,10 @@
 # Test changemaster mode:
 - name: Run replication with connection_name
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: changemaster
-    master_host: 127.0.0.1
+    master_host: '{{ mysql_host }}'
     master_port: "{{ primary_db.port }}"
     master_user: "{{ replication_user }}"
     master_password: "{{ replication_pass }}"
@@ -45,7 +45,7 @@
 # Test startslave mode:
 - name: Start slave with connection_name
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: startslave
     connection_name: "{{ conn_name }}"
@@ -59,7 +59,7 @@
 # Test getslave mode:
 - name: Get standby statu with connection_name
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: getslave
     connection_name: "{{ conn_name }}"
@@ -68,7 +68,7 @@
 - assert:
     that:
     - slave_status.Is_Slave == true
-    - slave_status.Master_Host == '127.0.0.1'
+    - slave_status.Master_Host == ''{{ mysql_host }}''
     - slave_status.Exec_Master_Log_Pos == primary_status.Position
     - slave_status.Master_Port == {{ primary_db.port }}
     - slave_status.Last_IO_Errno == 0
@@ -78,7 +78,7 @@
 # Test stopslave mode:
 - name: Stop slave with connection_name
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: stopslave
     connection_name: "{{ conn_name }}"
@@ -92,7 +92,7 @@
 # Test reset
 - name: Reset slave with connection_name
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: resetslave
     connection_name: "{{ conn_name }}"
@@ -106,7 +106,7 @@
 # Test reset all
 - name: Reset slave all with connection_name
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: resetslaveall
     connection_name: "{{ conn_name }}"
diff --git a/tests/integration/old_mariadb_replication/tasks/mariadb_replication_initial.yml b/tests/integration/old_mariadb_replication/tasks/mariadb_replication_initial.yml
index 86a6760..f65d090 100644
--- a/tests/integration/old_mariadb_replication/tasks/mariadb_replication_initial.yml
+++ b/tests/integration/old_mariadb_replication/tasks/mariadb_replication_initial.yml
@@ -3,11 +3,11 @@
 
 # Preparation:
 - name: Create user for replication
-  shell: "echo \"GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'localhost' IDENTIFIED BY '{{ replication_pass }}'; FLUSH PRIVILEGES;\" | mysql -P {{ primary_db.port }} -h 127.0.0.1"
+  shell: "echo \"GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'localhost' IDENTIFIED BY '{{ replication_pass }}'; FLUSH PRIVILEGES;\" | mysql -P {{ primary_db.port }} -h '{{ mysql_host }}'"
 
 - name: Create test database
   mysql_db:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ primary_db.port }}'
     state: present
     name: '{{ test_db }}'
@@ -16,12 +16,12 @@
   shell: 'mysqldump -P {{ primary_db.port }} -h 127.0.01 --all-databases --master-data=2 > {{ dump_path }}'
 
 - name: Restore the dump to the replica
-  shell: 'mysql -P {{ replica_db.port }} -h 127.0.0.1 < {{ dump_path }}'
+  shell: "mysql -P {{ replica_db.port }} -h '{{ mysql_host }}' < {{ dump_path }}"
 
 # Test getmaster mode:
 - name: Get master status
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ primary_db.port }}"
     mode: getmaster
   register: master_status
@@ -35,10 +35,10 @@
 # Test changemaster mode:
 - name: Run replication
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: changemaster
-    master_host: 127.0.0.1
+    master_host: '{{ mysql_host }}'
     master_port: "{{ primary_db.port }}"
     master_user: "{{ replication_user }}"
     master_password: "{{ replication_pass }}"
@@ -54,7 +54,7 @@
 # Test startslave mode:
 - name: Start slave
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: startslave
   register: result
@@ -67,7 +67,7 @@
 # Test getslave mode:
 - name: Get replica status
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: getslave
   register: slave_status
@@ -75,7 +75,7 @@
 - assert:
     that:
     - slave_status.Is_Slave == true
-    - slave_status.Master_Host == '127.0.0.1'
+    - slave_status.Master_Host == ''{{ mysql_host }}''
     - slave_status.Exec_Master_Log_Pos == master_status.Position
     - slave_status.Master_Port == {{ primary_db.port }}
     - slave_status.Last_IO_Errno == 0
@@ -85,7 +85,7 @@
 # Test stopslave mode:
 - name: Stop slave
   mysql_replication:
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: "{{ replica_db.port }}"
     mode: stopslave
   register: result
diff --git a/tests/integration/targets/setup_controller/tasks/fake_root.yml b/tests/integration/targets/setup_controller/tasks/fake_root.yml
new file mode 100644
index 0000000..49531b8
--- /dev/null
+++ b/tests/integration/targets/setup_controller/tasks/fake_root.yml
@@ -0,0 +1,11 @@
+---
+
+- name: "{{ role_name }} | Fake root | Ensure folder"
+  ansible.builtin.file:
+    path: "{{ playbook_dir }}/root"
+    state: directory
+
+- name: "{{ role_name }} | Fake root | Ensure default file exists"
+  ansible.builtin.file:
+    path: "{{ playbook_dir }}/root/.my.cnf"
+    state: touch
diff --git a/tests/integration/targets/setup_controller/tasks/main.yml b/tests/integration/targets/setup_controller/tasks/main.yml
new file mode 100644
index 0000000..0d5e36b
--- /dev/null
+++ b/tests/integration/targets/setup_controller/tasks/main.yml
@@ -0,0 +1,18 @@
+---
+####################################################################
+# WARNING: These are designed specifically for Ansible tests       #
+# and should not be used as examples of how to write Ansible roles #
+####################################################################
+
+- name: Prepare the fake root folder
+  ansible.builtin.import_tasks:
+    file: fake_root.yml
+
+# setvars.yml requires the iproute2 package installed by install.yml
+- name: Set variables
+  ansible.builtin.import_tasks:
+    file: setvars.yml
+
+- name: Verify all components version under test
+  ansible.builtin.import_tasks:
+    file: verify.yml
diff --git a/tests/integration/targets/setup_controller/tasks/setvars.yml b/tests/integration/targets/setup_controller/tasks/setvars.yml
new file mode 100644
index 0000000..d74136d
--- /dev/null
+++ b/tests/integration/targets/setup_controller/tasks/setvars.yml
@@ -0,0 +1,69 @@
+---
+
+- name: "{{ role_name }} | Setvars | Extract Podman/Docker Network Gateway"
+  ansible.builtin.shell:
+    cmd: ip route|grep default|awk '{print $3}'
+  register: ip_route_output
+
+- name: "{{ role_name }} | Setvars | Set Fact"
+  ansible.builtin.set_fact:
+    gateway_addr: "{{ ip_route_output.stdout }}"
+    connector_name_version: >-
+      {{ lookup(
+        'file',
+        '/root/ansible_collections/community/mysql/tests/integration/connector'
+      ) }}
+    db_engine_version: >-
+      {{ lookup(
+        'file',
+        '/root/ansible_collections/community/mysql/tests/integration/db_engine_version'
+      ) }}
+    python_version_lookup: >-
+      {{ lookup(
+        'file',
+        '/root/ansible_collections/community/mysql/tests/integration/python'
+      ) }}
+    ansible_version_lookup: >-
+      {{ lookup(
+        'file',
+        '/root/ansible_collections/community/mysql/tests/integration/ansible'
+      ) }}
+
+- name: "{{ role_name }} | Setvars | Set Fact using above facts"
+  ansible.builtin.set_fact:
+    connector_name: "{{ connector_name_version.split('=')[0].strip() }}"
+    connector_version: "{{ connector_name_version.split('=')[2].strip() }}"
+    db_engine: "{{ db_engine_version.split(':')[0].strip() }}"
+    db_version: "{{ db_engine_version.split(':')[1].strip() }}"
+    python_version: "{{ python_version_lookup.strip() }}"
+    test_ansible_version: >-
+      {%- if ansible_version_lookup == 'devel' -%}
+      {{ ansible_version_lookup }}
+      {%- else -%}
+      {{ ansible_version_lookup.split('-')[1].strip() }}
+      {%- endif -%}
+    mysql_command: >-
+      mysql
+      -h{{ gateway_addr }}
+      -P{{ mysql_primary_port }}
+      -u{{ mysql_user }}
+      -p{{ mysql_password }}
+      --protocol=tcp
+    mysql_command_wo_port: >-
+      mysql
+      -h{{ gateway_addr }}
+      -u{{ mysql_user }}
+      -p{{ mysql_password }}
+      --protocol=tcp
+
+- name: "{{ role_name }} | Setvars | Output test informations"
+  vars:
+    msg: |-
+      connector_name: {{ connector_name }}
+      connector_version: {{ connector_version }}
+      db_engine: {{ db_engine }}
+      db_version: {{ db_version }}
+      python_version: {{ python_version }}
+      test_ansible_version: {{ test_ansible_version }}
+  ansible.builtin.debug:
+    msg: "{{ msg.split('\n') }}"
diff --git a/tests/integration/targets/setup_controller/tasks/verify.yml b/tests/integration/targets/setup_controller/tasks/verify.yml
new file mode 100644
index 0000000..74aa0f2
--- /dev/null
+++ b/tests/integration/targets/setup_controller/tasks/verify.yml
@@ -0,0 +1,59 @@
+---
+
+- vars:
+    mysql_parameters: &mysql_params
+      login_user: root
+      login_password: msandbox
+      login_host: "{{ gateway_addr }}"
+      login_port: 3307
+
+  block:
+
+    - name: Query Primary container over TCP for MySQL/MariaDB version
+      mysql_info:
+        <<: *mysql_params
+        filter:
+          - version
+      register: primary_info
+
+    - name: Assert that test container runs the expected MySQL/MariaDB version
+      assert:
+        that:
+          - "'{{ primary_info.version.major }}.{{ primary_info.version.minor }}\
+          .{{ primary_info.version.release }}' == '{{ db_version }}'"
+
+    - name: Assert that mysql_info module used the expected version of pymysql
+      assert:
+        that:
+          - primary_info.connector_name == connector_name
+          - primary_info.connector_version == connector_version
+      when:
+        - connector_name == 'pymysql'
+
+    - name: Assert that mysql_info module used the expected version of mysqlclient
+      assert:
+        that:
+          - primary_info.connector_name == 'MySQLdb'
+          - primary_info.connector_version == connector_version
+      when:
+        - connector_name == 'mysqlclient'
+
+    - name: Display the python version in use
+      command:
+        cmd: python{{ python_version }} -V
+      changed_when: false
+      register: python_in_use
+
+    - name: Assert that expected Python is installed
+      assert:
+        that:
+          - python_in_use.stdout is search(python_version)
+
+    - name: Assert that we run the expected ansible version
+      assert:
+        that:
+          - >
+            "{{ ansible_version.major }}.{{ ansible_version.minor }}"
+            is version(test_ansible_version, '==')
+      when:
+        - test_ansible_version != 'devel'  # Devel will change overtime
diff --git a/tests/integration/targets/setup_mysql/defaults/main.yml b/tests/integration/targets/setup_mysql/defaults/main.yml
deleted file mode 100644
index cceb8f5..0000000
--- a/tests/integration/targets/setup_mysql/defaults/main.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-dbdeployer_version: 1.64.0
-dbdeployer_home_dir: /opt/dbdeployer
-
-home_dir: /root
-
-mariadb_install: false
-
-mysql_version: 8.0.22
-mariadb_version: 10.5.4
-
-mysql_base_port: 3306
-
-percona_client_package: >-
-  {%- if mariadb_install -%}
-    mariadb-client
-  {%- else -%}
-    percona-server-client-5.7
-  {%- endif -%}
diff --git a/tests/integration/targets/setup_mysql/handlers/main.yml b/tests/integration/targets/setup_mysql/handlers/main.yml
deleted file mode 100644
index 090a5e7..0000000
--- a/tests/integration/targets/setup_mysql/handlers/main.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-- name: "{{ role_name }} | handler | create dbdeployer installed file"
-  template:
-    src: installed_file.j2
-    dest: "{{ dbdeployer_installed_file }}"
-  listen: create zookeeper installed file
diff --git a/tests/integration/targets/setup_mysql/tasks/config.yml b/tests/integration/targets/setup_mysql/tasks/config.yml
deleted file mode 100644
index 2b27e27..0000000
--- a/tests/integration/targets/setup_mysql/tasks/config.yml
+++ /dev/null
@@ -1,15 +0,0 @@
----
-- name: "{{ role_name }} | config | download mysql tarball"
-  get_url:
-    url: "{{ install_src }}"
-    dest: "{{ dbdeployer_sandbox_download_dir }}/{{ install_tarball }}"
-
-- name: "{{ role_name }} | config | run unpack tarball"
-  shell:
-    cmd: "dbdeployer unpack {{ dbdeployer_sandbox_download_dir }}/{{ install_tarball }} --flavor {{ install_type }}"
-    creates: "{{ dbdeployer_sandbox_binary_dir }}/{{ install_version }}"
-
-- name: "{{ role_name }} | config | setup replication topology"
-  shell:
-    cmd: "dbdeployer deploy multiple {{ install_version }} --flavor {{ install_type }} --base-port {{ mysql_base_port }} --my-cnf-options=\"master_info_repository='TABLE'\" --my-cnf-options=\"relay_log_info_repository='TABLE'\""
-    creates: "{{ dbdeployer_sandbox_home_dir }}/multi_msb_{{ install_version|replace('.','_') }}"
diff --git a/tests/integration/targets/setup_mysql/tasks/dir.yml b/tests/integration/targets/setup_mysql/tasks/dir.yml
deleted file mode 100644
index dc02879..0000000
--- a/tests/integration/targets/setup_mysql/tasks/dir.yml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-- name: "{{ role_name }} | dir | create dbdeployer directories"
-  file:
-    state: directory
-    path: "{{ item }}"
-  loop:
-    - "{{ dbdeployer_home_dir }}"
-    - "{{ dbdeployer_install_dir }}"
-    - "{{ dbdeployer_sandbox_download_dir }}"
-    - "{{ dbdeployer_sandbox_binary_dir }}"
-    - "{{ dbdeployer_sandbox_home_dir }}"
diff --git a/tests/integration/targets/setup_mysql/tasks/install.yml b/tests/integration/targets/setup_mysql/tasks/install.yml
deleted file mode 100644
index b64af25..0000000
--- a/tests/integration/targets/setup_mysql/tasks/install.yml
+++ /dev/null
@@ -1,90 +0,0 @@
----
-- name: "{{ role_name }} | install | add apt signing key for percona"
-  apt_key:
-    keyserver: keyserver.ubuntu.com
-    id: 4D1BB29D63D98E422B2113B19334A25F8507EFA5
-    state: present
-  when: install_type == 'mysql'
-
-- name: "{{ role_name }} | install | add percona repositories"
-  apt_repository:
-    repo: deb http://repo.percona.com/percona/apt {{ ansible_lsb.codename }} main
-    state: present
-  when: install_type == 'mysql'
-
-- name: "{{ role_name }} | install | add apt signing key for mariadb"
-  apt_key:
-    keyserver: keyserver.ubuntu.com
-    id: F1656F24C74CD1D8
-    state: present
-  when: install_type == 'mariadb'
-
-- name: "{{ role_name }} | install | add mariadb repositories"
-  apt_repository:
-    repo: "deb [arch=amd64,arm64] https://downloads.mariadb.com/MariaDB/mariadb-{{ mysql_major_version }}/repo/ubuntu {{ ansible_lsb.codename }} main"
-    state: present
-  when: install_type == 'mariadb'
-
-- name: "{{ role_name }} | install | install packages required by percona"
-  apt:
-    name: "{{ percona_mysql_packages }}"
-    state: present
-  environment:
-    DEBIAN_FRONTEND: noninteractive
-
-- name: "{{ role_name }} | install | install packages required by mysql connector"
-  apt:
-    name: "{{ install_python_prereqs }}"
-    state: present
-  environment:
-    DEBIAN_FRONTEND: noninteractive
-
-- name: "{{ role_name }} | install | install python packages"
-  pip:
-    name: "{{ python_packages }}"
-  register: connector
-
-- name: Extract connector.name.0 content
-  set_fact:
-    connector_name: "{{ connector.name.0 }}"
-
-- name: Debug connector_name content
-  debug:
-    msg: '{{ connector_name }}'
-
-- name: Extract connector version
-  set_fact:
-    connector_ver: "{{ connector_name.split('=')[2].strip() }}"
-
-- name: Debug connector_ver var content
-  debug:
-    msg: '{{ connector_ver }}'
-
-- name: "{{ role_name }} | install | install packages required by mysql"
-  apt:
-    name: "{{ install_prereqs }}"
-    state: present
-  environment:
-    DEBIAN_FRONTEND: noninteractive
-
-- name: "{{ role_name }} | install | download and unpack dbdeployer"
-  unarchive:
-    remote_src: true
-    src: "{{ dbdeployer_src }}"
-    dest: "{{ dbdeployer_install_dir }}"
-    creates: "{{ dbdeployer_installed_file }}"
-  register: dbdeployer_tarball_install
-  notify:
-    - create zookeeper installed file
-  until: dbdeployer_tarball_install is not failed
-  retries: 6
-  delay: 5
-
-- name: "{{ role_name }} | install | create symlink"
-  file:
-    src: "{{ dbdeployer_install_dir }}/dbdeployer-{{ dbdeployer_version }}.linux"
-    dest: /usr/local/bin/dbdeployer
-    follow: false
-    state: link
-
-- meta: flush_handlers
diff --git a/tests/integration/targets/setup_mysql/tasks/main.yml b/tests/integration/targets/setup_mysql/tasks/main.yml
deleted file mode 100644
index c6a8348..0000000
--- a/tests/integration/targets/setup_mysql/tasks/main.yml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-####################################################################
-# WARNING: These are designed specifically for Ansible tests       #
-# and should not be used as examples of how to write Ansible roles #
-####################################################################
-
-- import_tasks: setvars.yml
-- import_tasks: dir.yml
-- import_tasks: install.yml
-- import_tasks: config.yml
-- import_tasks: verify.yml
diff --git a/tests/integration/targets/setup_mysql/tasks/setvars.yml b/tests/integration/targets/setup_mysql/tasks/setvars.yml
deleted file mode 100644
index cfc90c1..0000000
--- a/tests/integration/targets/setup_mysql/tasks/setvars.yml
+++ /dev/null
@@ -1,33 +0,0 @@
----
-- name: "{{ role_name }} | setvars | split mysql version in parts"
-  set_fact:
-    mysql_version_parts: >-
-      {%- if mariadb_install -%}
-      {{ mariadb_version.split('.') }}
-      {%- else -%}
-      {{ mysql_version.split('.') }}
-      {%- endif -%}
-
-- name: "{{ role_name }} | setvars | get mysql major version"
-  set_fact:
-    mysql_major_version: "{{ mysql_version_parts[0] + '.' + mysql_version_parts[1] }}"
-
-- name: "{{ role_name }} | setvars | set the appropriate extension dependent on the mysql version"
-  set_fact:
-    mysql_compression_extension: "{{ mysql_version is version('8.0.0', '<') | ternary('gz', 'xz') }}"
-
-- name: "{{ role_name }} | setvars | set the install type"
-  set_fact:
-    install_type: "{{ mariadb_install | ternary('mariadb', 'mysql') }}"
-
-- name: "{{ role_name }} | setvars | set install_version"
-  set_fact:
-    install_version: "{{ lookup('vars', install_type + '_version') }}"
-
-- name: "{{ role_name }} | setvars | set install_tarball"
-  set_fact:
-    install_tarball: "{{ lookup('vars', install_type + '_tarball') }}"
-
-- name: "{{ role_name }} | setvars | set install_src"
-  set_fact:
-    install_src: "{{ lookup('vars', install_type + '_src') }}"
diff --git a/tests/integration/targets/setup_mysql/tasks/verify.yml b/tests/integration/targets/setup_mysql/tasks/verify.yml
deleted file mode 100644
index ca383d9..0000000
--- a/tests/integration/targets/setup_mysql/tasks/verify.yml
+++ /dev/null
@@ -1,27 +0,0 @@
----
-- name: "{{ role_name }} | verify | confirm primary is running and get the port"
-  shell: "{{ dbdeployer_sandbox_home_dir }}/multi_msb_{{ install_version|replace('.','_') }}/n1 -BNe'select @@port'"
-  register: primary_port
-
-- name: "{{ role_name }} | verify | confirm replica1 is running and get the port"
-  shell: "{{ dbdeployer_sandbox_home_dir }}/multi_msb_{{ install_version|replace('.','_') }}/n2 -BNe'select @@port'"
-  register: replica1_port
-
-- name: "{{ role_name }} | verify | confirm replica2 is running and get the port"
-  shell: "{{ dbdeployer_sandbox_home_dir }}/multi_msb_{{ install_version|replace('.','_') }}/n3 -BNe'select @@port'"
-  register: replica2_port
-
-- name: "{{ role_name }} | verify | confirm primary is running on expected port"
-  assert:
-    that:
-      - primary_port.stdout|int == 3307
-
-- name: "{{ role_name }} | verify | confirm replica1 is running on expected port"
-  assert:
-    that:
-      - replica1_port.stdout|int == 3308
-
-- name: "{{ role_name }} | verify | confirm replica2 is running on expected port"
-  assert:
-    that:
-      - replica2_port.stdout|int == 3309
diff --git a/tests/integration/targets/setup_mysql/templates/installed_file.j2 b/tests/integration/targets/setup_mysql/templates/installed_file.j2
deleted file mode 100644
index 862a357..0000000
--- a/tests/integration/targets/setup_mysql/templates/installed_file.j2
+++ /dev/null
@@ -1 +0,0 @@
-{{ dbdeployer_version }}
diff --git a/tests/integration/targets/setup_mysql/vars/main.yml b/tests/integration/targets/setup_mysql/vars/main.yml
deleted file mode 100644
index 8fbcd90..0000000
--- a/tests/integration/targets/setup_mysql/vars/main.yml
+++ /dev/null
@@ -1,30 +0,0 @@
----
-dbdeployer_install_dir: "{{ dbdeployer_home_dir }}/dbdeployer_{{ dbdeployer_version }}"
-dbdeployer_src: "https://github.com/datacharmer/dbdeployer/releases/download/v{{ dbdeployer_version }}/dbdeployer-{{ dbdeployer_version }}.linux.tar.gz"
-dbdeployer_installed_file: "{{ dbdeployer_home_dir }}/dbdeployer_installed"
-
-dbdeployer_sandbox_download_dir: "{{ home_dir }}/downloads"
-dbdeployer_sandbox_binary_dir: "{{ home_dir }}/opt/mysql"
-dbdeployer_sandbox_home_dir: "{{ home_dir }}/sandboxes"
-
-percona_mysql_packages:
-  - "{{ percona_client_package }}"
-
-python_packages: [pymysql == 0.9.3]
-
-install_prereqs:
-  - libaio1
-  - libnuma1
-  - libncurses5
-
-install_python_prereqs:
-  - python3-dev
-  - python3-cryptography
-  - default-libmysqlclient-dev
-  - build-essential
-
-mysql_tarball: "mysql-{{ mysql_version }}-linux-glibc2.12-x86_64.tar.{{ mysql_compression_extension }}"
-mysql_src: "https://cdn.mysql.com/archives/mysql-{{ mysql_major_version }}/{{ mysql_tarball }}"
-mariadb_url_subdir: "linux"
-mariadb_tarball: "mariadb-{{ mariadb_version }}-{{ mariadb_url_subdir }}-x86_64.tar.gz"
-mariadb_src: "https://downloads.mariadb.com/MariaDB/mariadb-{{ mariadb_version }}/bintar-{{ mariadb_url_subdir }}-x86_64/{{ mariadb_tarball }}"
diff --git a/tests/integration/targets/test_mysql_db/defaults/main.yml b/tests/integration/targets/test_mysql_db/defaults/main.yml
index 1c1577b..fb523dd 100644
--- a/tests/integration/targets/test_mysql_db/defaults/main.yml
+++ b/tests/integration/targets/test_mysql_db/defaults/main.yml
@@ -2,6 +2,7 @@
 # defaults file for test_mysql_db
 mysql_user: root
 mysql_password: msandbox
+mysql_host: '{{ gateway_addr }}'
 mysql_primary_port: 3307
 
 # Database names
diff --git a/tests/integration/targets/test_mysql_db/meta/main.yml b/tests/integration/targets/test_mysql_db/meta/main.yml
index f1174ff..aebda43 100644
--- a/tests/integration/targets/test_mysql_db/meta/main.yml
+++ b/tests/integration/targets/test_mysql_db/meta/main.yml
@@ -1,2 +1,2 @@
 dependencies:
-  - setup_mysql
+  - setup_controller
diff --git a/tests/integration/targets/test_mysql_db/tasks/config_overrides_defaults.yml b/tests/integration/targets/test_mysql_db/tasks/config_overrides_defaults.yml
index c2fda2a..390c6ae 100644
--- a/tests/integration/targets/test_mysql_db/tasks/config_overrides_defaults.yml
+++ b/tests/integration/targets/test_mysql_db/tasks/config_overrides_defaults.yml
@@ -1,57 +1,59 @@
-- set_fact:
+---
+- name: Config overrides | Set facts
+  set_fact:
     db_to_create: testdb1
-    config_file: "/root/.my1.cnf"
+    config_file: "{{ playbook_dir }}/.my1.cnf"
     fake_port: 9999
     fake_host: "blahblah.local"
-    include_dir: "/root/mycnf.d"
+    include_dir: "{{ playbook_dir }}/mycnf.d"
 
-- name: Create custom config file
+- name: Config overrides | Create custom config file
   shell: 'echo "[client]" > {{ config_file }}'
 
-- name: Add fake port to config file
+- name: Config overrides | Add fake port to config file
   shell: 'echo "port = {{ fake_port }}" >> {{ config_file }}'
 
-- name: Add blank line
+- name: Config overrides | Add blank line
   shell: 'echo "" >> {{ config_file }}'
   when:
     - >
-      connector_name is not search('pymysql')
+      connector_name != 'pymysql'
       or (
-        connector_name is search('pymysql')
-        and connector_ver is version('0.9.3', '>=')
+        connector_name == 'pymysql'
+        and connector_version is version('0.9.3', '>=')
       )
 
-- name: Create include_dir
+- name: Config overrides | Create include_dir
   file:
     path: '{{ include_dir }}'
     state: directory
     mode: '0777'
   when:
     - >
-      connector_name is not search('pymysql')
+      connector_name != 'pymysql'
       or (
-        connector_name is search('pymysql')
-        and connector_ver is version('0.9.3', '>=')
+        connector_name == 'pymysql'
+        and connector_version is version('0.9.3', '>=')
       )
 
-- name: Add include_dir
+- name: Config overrides | Add include_dir
   lineinfile:
     path: '{{ config_file }}'
     line: '!includedir {{ include_dir }}'
     insertafter: EOF
   when:
     - >
-      connector_name is not search('pymysql')
+      connector_name != 'pymysql'
       or (
-        connector_name is search('pymysql')
-        and connector_ver is version('0.9.3', '>=')
+        connector_name == 'pymysql'
+        and connector_version is version('0.9.3', '>=')
       )
 
-- name: Create database using fake port to connect to, must fail
+- name: Config overrides | Create database using fake port to connect to, must fail
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_to_create }}'
     state: present
@@ -61,17 +63,17 @@
   ignore_errors: yes
   register: result
 
-- name: Must fail because login_port default has beed overriden by wrong value from config file
+- name: Config overrides | Must fail because login_port default has beed overriden by wrong value from config file
   assert:
     that:
-    - result is failed
-    - result.msg is search("unable to connect to database")
+      - result is failed
+      - result.msg is search("unable to connect to database")
 
-- name: Create database using default port
+- name: Config overrides | Create database using default port
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_to_create }}'
     state: present
@@ -80,22 +82,22 @@
     config_overrides_defaults: no
   register: result
 
-- name: Must not fail because of the default of login_port is correct
+- name: Config overrides | Must not fail because of the default of login_port is correct
   assert:
     that:
-    - result is changed
+      - result is changed
 
-- name: Reinit custom config file
+- name: Config overrides | Reinit custom config file
   shell: 'echo "[client]" > {{ config_file }}'
 
-- name: Add fake host to config file
+- name: Config overrides | Add fake host to config file
   shell: 'echo "host = {{ fake_host }}" >> {{ config_file }}'
 
-- name: Remove database using fake login_host
+- name: Config overrides | Remove database using fake login_host
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_to_create }}'
     state: absent
@@ -104,18 +106,17 @@
   register: result
   ignore_errors: yes
 
-- name: Must fail because login_host default has beed overriden by wrong value from config file
+- name: Config overrides | Must fail because login_host default has beed overriden by wrong value from config file
   assert:
     that:
-    - result is failed
-    - result.msg is search("Can't connect to MySQL server on '{{ fake_host }}'") or result.msg is search("Unknown MySQL server host '{{ fake_host }}'")
+      - result is failed
+      - result.msg is search("Can't connect to MySQL server on '{{ fake_host }}'") or result.msg is search("Unknown MySQL server host '{{ fake_host }}'")
 
-# Clean up
-- name: Remove test db
+- name: Config overrides | Clean up test database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_to_create }}'
     state: absent
diff --git a/tests/integration/targets/test_mysql_db/tasks/encoding_dump_import.yml b/tests/integration/targets/test_mysql_db/tasks/encoding_dump_import.yml
index 9ef3af5..02e5df2 100644
--- a/tests/integration/targets/test_mysql_db/tasks/encoding_dump_import.yml
+++ b/tests/integration/targets/test_mysql_db/tasks/encoding_dump_import.yml
@@ -1,45 +1,46 @@
 ---
 
-- set_fact:
-    latin1_file1: "{{tmp_dir}}/{{file}}"
+- name: Encoding | Set fact
+  set_fact:
+    latin1_file1: "{{ tmp_dir }}/{{ file }}"
 
 - name: Deleting Latin1 encoded Database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_latin1_name }}'
     state: absent
 
-- name: create Latin1 encoded database
+- name: Encoding | Create Latin1 encoded database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_latin1_name }}'
     state: present
     encoding: latin1
 
-- name: create a table in Latin1 database
+- name: Encoding | Create a table in Latin1 database
   command: "{{ mysql_command }} {{ db_latin1_name }} -e \"create table testlatin1(id int, name varchar(100))\""
 
 
 # Inserting a string in latin1 into table, , this string be tested later,
 # so report any change of content in the test too
-- name: inserting data into Latin1 database
+- name: Encoding | Inserting data into Latin1 database
   command: "{{ mysql_command }} {{ db_latin1_name }} -e \"insert into testlatin1 value(47,'Amédée Bôlüt')\""
 
-- name: selecting table
+- name: Encoding | Selecting table
   command: "{{ mysql_command }} {{ db_latin1_name }} -e \"select * from testlatin1\""
   register: output
 
-- name: Dumping a table in Latin1 database
+- name: Encoding | Dumping a table in Latin1 database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: "{{ db_latin1_name }}"
     encoding: latin1
@@ -49,30 +50,30 @@
 
 - assert:
     that:
-    - result is changed
+      - result is changed
 
-- name: state dump - file name should exist
+- name: Encoding | State dump - file name should exist (latin1_file1)
   file:
     name: '{{ latin1_file1 }}'
     state: file
 
-- name:  od the file and check of latin1 encoded string is present
+- name: od the file and check of latin1 encoded string is present
   shell: grep -a 47 {{ latin1_file1 }} | od -c |grep "A   m 351   d 351   e       B 364\|A   m 303 251   d 303 251   e       B 303"
 
-- name: Dropping {{ db_latin1_name }} database
+- name: Encoding | Dropping {{ db_latin1_name }} database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_latin1_name }}'
     state: absent
 
-- name: Importing the latin1 mysql script
+- name: Encoding | Importing the latin1 mysql script
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     state: import
     encoding: latin1
@@ -80,20 +81,25 @@
     target: "{{ latin1_file1 }}"
   register: result
 
-- assert:
+- name: Encoding | Assert that importing latin1 is changed
+  assert:
     that:
-    - result is changed
+      - result is changed
 
-- name: check encoding of table
-  shell: "{{ mysql_command }} {{ db_latin1_name }} -e \"SHOW FULL COLUMNS FROM testlatin1\""
+- name: Encoding | Check encoding of table
+  ansible.builtin.command:
+    cmd: >
+      {{ mysql_command }}
+      {{ db_latin1_name }}
+      -e "SHOW FULL COLUMNS FROM {{ db_latin1_name }}.testlatin1"
   register: output
   failed_when: '"latin1_swedish_ci" not in output.stdout'
 
-- name: remove database
+- name: Encoding | Clean up database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_latin1_name }}'
     state: absent
diff --git a/tests/integration/targets/test_mysql_db/tasks/issue-28.yml b/tests/integration/targets/test_mysql_db/tasks/issue-28.yml
index 54ff5a7..8ca0dc7 100644
--- a/tests/integration/targets/test_mysql_db/tasks/issue-28.yml
+++ b/tests/integration/targets/test_mysql_db/tasks/issue-28.yml
@@ -9,7 +9,7 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
   when: tls_enabled
   block:
@@ -26,6 +26,7 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
+        host_all: true
         state: absent
       ignore_errors: yes
 
@@ -33,6 +34,7 @@
       mysql_user:
         <<: *mysql_params
         name: "{{ user_name_1 }}"
+        host: "%"
         password: "{{ user_password_1 }}"
         priv: '*.*:ALL,GRANT'
         tls_requires:
@@ -44,7 +46,7 @@
         state: absent
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
       register: result
@@ -53,12 +55,14 @@
     - assert:
         that:
           - result is failed
-      when: connector_name is search('pymysql')
+      when:
+        - connector_name == 'pymysql'
 
     - assert:
         that:
           - result is succeeded
-      when: connector_name is not search('pymysql')
+      when:
+        - connector_name != 'pymysql'
 
     - name: attempt connection with newly created user ignoring hostname
       mysql_db:
@@ -66,7 +70,7 @@
         state: absent
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
         check_hostname: no
@@ -81,5 +85,5 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
-        host: 127.0.0.1
+        host_all: true
         state: absent
diff --git a/tests/integration/targets/test_mysql_db/tasks/issue_256_mysqldump_errors.yml b/tests/integration/targets/test_mysql_db/tasks/issue_256_mysqldump_errors.yml
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration/targets/test_mysql_db/tasks/main.yml b/tests/integration/targets/test_mysql_db/tasks/main.yml
index 958e341..42fb596 100644
--- a/tests/integration/targets/test_mysql_db/tasks/main.yml
+++ b/tests/integration/targets/test_mysql_db/tasks/main.yml
@@ -1,3 +1,4 @@
+---
 ####################################################################
 # WARNING: These are designed specifically for Ansible tests       #
 # and should not be used as examples of how to write Ansible roles #
@@ -21,10 +22,6 @@
 # You should have received a copy of the GNU General Public License
 # along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
 
-- name: alias mysql command to include default options
-  set_fact:
-    mysql_command: "mysql -u{{ mysql_user }} -p{{ mysql_password }} -P{{ mysql_primary_port }} --protocol=tcp"
-
 - name: Check state present/absent
   include_tasks: state_present_absent.yml
   vars:
diff --git a/tests/integration/targets/test_mysql_db/tasks/multi_db_create_delete.yml b/tests/integration/targets/test_mysql_db/tasks/multi_db_create_delete.yml
index c2eb13c..0bd7d58 100644
--- a/tests/integration/targets/test_mysql_db/tasks/multi_db_create_delete.yml
+++ b/tests/integration/targets/test_mysql_db/tasks/multi_db_create_delete.yml
@@ -18,7 +18,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
@@ -43,7 +43,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
@@ -75,7 +75,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
@@ -107,7 +107,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
@@ -139,7 +139,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
@@ -170,7 +170,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db2_name }}'
@@ -199,7 +199,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
@@ -231,7 +231,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
@@ -271,7 +271,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
@@ -308,7 +308,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - "{{ db1_name }}"
@@ -348,7 +348,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - "{{ db4_name }}"
@@ -384,11 +384,12 @@
 
 # ==========================================================================
 # Dump existing databases
+
 - name: Dump existing databases
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
@@ -398,13 +399,13 @@
     target: '{{ dump1_file }}'
   register: dump_result
 
-- name: assert successful completion of dump operation
+- name: Assert successful completion of dump operation (existing database)
   assert:
     that:
       - dump_result is changed
       - dump_result.db_list == ['{{ db1_name }}', '{{ db2_name }}', '{{ db3_name }}']
 
-- name: run command to list databases like specified database name
+- name: Run command to list databases like specified database name
   command: "{{ mysql_command }} \"-e show databases like 'database%'\""
   register: mysql_result
 
@@ -415,7 +416,7 @@
       - "'{{ db2_name }}' in mysql_result.stdout"
       - "'{{ db3_name }}' in mysql_result.stdout"
 
-- name: state dump - file name should exist
+- name: State dump - file name should exist (dump1_file)
   file:
     name: '{{ dump1_file }}'
     state: file
@@ -441,7 +442,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: all
     state: dump
@@ -466,7 +467,7 @@
       - "'{{ db4_name }}' not in mysql_result.stdout"
       - "'{{ db5_name }}' not in mysql_result.stdout"
 
-- name: state dump - file name should exist
+- name: state dump - file name should exist (dump2_file)
   file:
     name: '{{ dump2_file }}'
     state: file
@@ -479,7 +480,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db2_name }}'
@@ -509,7 +510,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db2_name }}'
@@ -539,7 +540,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db2_name }}'
@@ -569,7 +570,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db2_name }}'
@@ -598,7 +599,7 @@
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db1_name }}'
diff --git a/tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml b/tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml
index 6d904b9..5df8a1d 100644
--- a/tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml
+++ b/tests/integration/targets/test_mysql_db/tasks/state_dump_import.yml
@@ -17,113 +17,116 @@
 # along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
 
 # ============================================================
-- set_fact:
+- name: Dump and Import | Set facts
+  set_fact:
     db_file_name: "{{ tmp_dir }}/{{ file }}"
     wrong_sql_file: "{{ tmp_dir }}/wrong.sql"
     dump_file1: "{{ tmp_dir }}/{{ file2 }}"
     dump_file2: "{{ tmp_dir }}/{{ file3 }}"
     db_user: "test"
     db_user_unsafe_password: "pass!word"
-    config_file: "/root/.my.cnf"
+    config_file: "{{ playbook_dir }}/root/.my.cnf"
 
-- name: create custom config file
+- name: Dump and Import | Create custom config file
   shell: 'echo "[client]" > {{ config_file }}'
 
-- name: create user for test unsafe_login_password parameter
+- name: Dump and Import | Create user for test unsafe_login_password parameter
   mysql_user:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_user }}'
+    host: '%'
     password: '{{ db_user_unsafe_password }}'
     priv: '*.*:ALL'
     state: present
 
-- name: state dump/import - create database
+- name: Dump and Import | State dump/import - create database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name }}'
     state: present
     check_implicit_admin: yes
 
-- name: create database
+- name: Dump and Import | Create database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name2 }}'
     state: present
     check_implicit_admin: no
 
-- name: state dump/import - create table department
+- name: Dump and Import | State dump/import - create table department
   command: "{{ mysql_command }} {{ db_name }} \"-e create table department(id int, name varchar(100))\""
 
-- name: state dump/import - create table employee
+- name: Dump and Import | State dump/import - create table employee
   command: "{{ mysql_command }} {{ db_name }} \"-e create table employee(id int, name varchar(100))\""
 
-- name: state dump/import - insert data into table employee
+- name: Dump and Import | State dump/import - insert data into table employee
   command: "{{ mysql_command }} {{ db_name }} \"-e insert into employee value(47,'Joe Smith')\""
 
-- name: state dump/import - insert data into table department
+- name: Dump and Import | State dump/import - insert data into table department
   command: "{{ mysql_command }} {{ db_name }} \"-e insert into department value(2,'Engineering')\""
 
-- name: state dump/import - file name should not exist
+- name: Dump and Import | State dump/import - file name should not exist
   file:
     name: '{{ db_file_name }}'
     state: absent
 
-- name: database dump file1 should not exist
+- name: Dump and Import | Database dump file1 should not exist
   file:
     name: '{{ dump_file1 }}'
     state: absent
 
-- name: database dump file2 should not exist
+- name: Dump and Import | Database dump file2 should not exist
   file:
     name: '{{ dump_file2 }}'
     state: absent
 
-- name: state dump without department table.
+- name: Dump and Import | State dump without department table.
   mysql_db:
     login_user: '{{ db_user }}'
     login_password: '{{ db_user_unsafe_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     unsafe_login_password: yes
     name: '{{ db_name }}'
     state: dump
     target: '{{ db_file_name }}'
     ignore_tables:
-        - "{{ db_name }}.department"
+      - "{{ db_name }}.department"
     force: yes
     master_data: 1
     skip_lock_tables: yes
-    dump_extra_args: --skip-triggers
+    dump_extra_args: >-
+      --skip-triggers
     config_file: '{{ config_file }}'
     restrict_config_file: yes
     check_implicit_admin: no
   register: result
 
-- name: assert successful completion of dump operation
+- name: Dump and Import | Assert successful completion of dump operation
   assert:
     that:
       - result is changed
-      - result.executed_commands[0] is search("mysqldump --defaults-file={{ config_file }} --user={{ db_user }} --password=\*\*\*\*\*\*\*\* --force --host=127.0.0.1 --port={{ mysql_primary_port }} {{ db_name }} --skip-lock-tables --quick --ignore-table={{ db_name }}.department --master-data=1 --skip-triggers")
+      - result.executed_commands[0] is search(".department --master-data=1 --skip-triggers")
 
-- name: state dump/import - file name should exist
+- name: Dump and Import | State dump/import - file name should exist (db_file_name)
   file:
     name: '{{ db_file_name }}'
     state: file
 
-- name: state dump with multiple databases in comma separated form.
+- name: Dump and Import | State dump with multiple databases in comma separated form for MySQL.
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: "{{ db_name }},{{ db_name2 }}"
     state: dump
@@ -131,22 +134,22 @@
     check_implicit_admin: yes
   register: dump_result1
 
-- name: assert successful completion of dump operation (with multiple databases in comma separated form)
+- name: Dump and Import | Assert successful completion of dump operation (with multiple databases in comma separated form)
   assert:
     that:
       - dump_result1 is changed
       - dump_result1.executed_commands[0] is search(" --user=root --password=\*\*\*\*\*\*\*\*")
 
-- name: state dump - dump file1 should exist
+- name: Dump and Import | State dump - dump file1 should exist
   file:
     name: '{{ dump_file1 }}'
     state: file
 
-- name: state dump with multiple databases in list form via check_mode
+- name: Dump and Import | State dump with multiple databases in list form via check_mode
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db_name }}'
@@ -156,26 +159,26 @@
   register: dump_result
   check_mode: yes
 
-- name: assert successful completion of dump operation (with multiple databases in list form) via check mode
+- name: Dump and Import | Assert successful completion of dump operation (with multiple databases in list form) via check mode
   assert:
     that:
       - dump_result is changed
 
-- name: database dump file2 should not exist
+- name: Dump and Import | Database dump file2 should not exist
   stat:
     path: '{{ dump_file2 }}'
   register: stat_result
 
-- name: assert that check_mode does not create dump file for databases
+- name: Dump and Import | Assert that check_mode does not create dump file for databases
   assert:
     that:
       - stat_result.stat.exists is defined and not stat_result.stat.exists
 
-- name: state dump with multiple databases in list form.
+- name: Dump and Import | State dump with multiple databases in list form.
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name:
       - '{{ db_name }}'
@@ -184,39 +187,39 @@
     target: '{{ dump_file2 }}'
   register: dump_result2
 
-- name: assert successful completion of dump operation (with multiple databases in list form)
+- name: Dump and Import | Assert successful completion of dump operation (with multiple databases in list form)
   assert:
     that:
       - dump_result2 is changed
 
-- name: state dump - dump file2 should exist
+- name: Dump and Import | State dump - dump file2 should exist
   file:
     name: '{{ dump_file2 }}'
     state: file
 
-- name: state dump/import - remove database
+- name: Dump and Import | State dump/import - remove database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name }}'
     state: absent
 
-- name: remove database
+- name: Dump and Import | Remove database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name2 }}'
     state: absent
 
-- name: test state=import to restore the database of type {{ format_type }} (expect changed=true)
+- name: Dump and Import | Test state=import to restore the database of type {{ format_type }} (expect changed=true)
   mysql_db:
     login_user: '{{ db_user }}'
     login_password: '{{ db_user_unsafe_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     unsafe_login_password: yes
     name: '{{ db_name }}'
@@ -225,20 +228,20 @@
     use_shell: yes
   register: result
 
-- name: show the tables
+- name: Dump and Import | Show the tables
   command: "{{ mysql_command }} {{ db_name }} \"-e show tables\""
   register: result
 
-- name: assert that the department table is absent.
+- name: Dump and Import | Assert that the department table is absent.
   assert:
     that:
       - "'department' not in result.stdout"
 
-- name: test state=import to restore a database from multiple database dumped file1
+- name: Dump and Import | Test state=import to restore a database from multiple database dumped file1
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name2 }}'
     state: import
@@ -246,34 +249,34 @@
     use_shell: no
   register: import_result
 
-- name: assert output message restored a database from dump file1
+- name: Dump and Import | Assert output message restored a database from dump file1
   assert:
     that:
       - import_result is changed
 
-- name: remove database
+- name: Dump and Import | Remove database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name2 }}'
     state: absent
 
-- name: run command to list databases
+- name: Dump and Import | Run command to list databases
   command: "{{ mysql_command }} \"-e show databases like 'data%'\""
   register: mysql_result
 
-- name: assert that db_name2 database does not exist
+- name: Dump and Import | Assert that db_name2 database does not exist
   assert:
     that:
       - "'{{ db_name2 }}' not in mysql_result.stdout"
 
-- name: test state=import to restore a database from dumped file2 (check mode)
+- name: Dump and Import | Test state=import to restore a database from dumped file2 (check mode)
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name2 }}'
     state: import
@@ -281,96 +284,96 @@
   register: check_import_result
   check_mode: yes
 
-- name: assert output message restored a database from dump file2 (check mode)
+- name: Dump and Import | Assert output message restored a database from dump file2 (check mode)
   assert:
     that:
       - check_import_result is changed
 
-- name: run command to list databases
+- name: Dump and Import | Run command to list databases
   command: "{{ mysql_command }} \"-e show databases like 'data%'\""
   register: mysql_result
 
-- name: assert that db_name2 database does not exist (check mode)
+- name: Dump and Import | Assert that db_name2 database does not exist (check mode)
   assert:
     that:
       - "'{{ db_name2 }}' not in mysql_result.stdout"
 
-- name: test state=import to restore a database from multiple database dumped file2
+- name: Dump and Import | Test state=import to restore a database from multiple database dumped file2
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name2 }}'
     state: import
     target: '{{ dump_file2 }}'
   register: import_result2
 
-- name: assert output message restored a database from dump file2
+- name: Dump and Import | Assert output message restored a database from dump file2
   assert:
     that:
       - import_result2 is changed
       - import_result2.db_list == ['{{ db_name2 }}']
 
-- name: run command to list databases
+- name: Dump and Import | Run command to list databases
   command: "{{ mysql_command }} \"-e show databases like 'data%'\""
   register: mysql_result
 
-- name: assert that db_name2 database does exist after import
+- name: Dump and Import | Assert that db_name2 database does exist after import
   assert:
     that:
       - "'{{ db_name2 }}' in mysql_result.stdout"
 
-- name: test state=dump to backup the database of type {{ format_type }} (expect changed=true)
+- name: Dump and Import | Test state=dump to backup the database of type {{ format_type }} (expect changed=true)
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name }}'
     state: dump
     target: '{{ db_file_name }}'
   register: result
 
-- name: assert output message backup the database
+- name: Dump and Import | Assert output message backup the database
   assert:
     that:
       - result is changed
       - "result.db =='{{ db_name }}'"
 
-# - name: assert database was backed up successfully
+# - name: Dump and Import | Assert database was backed up successfully
 #   command: "file {{ db_file_name }}"
 #   register: result
 #
-# - name: assert file format type
+# - name: Dump and Import | Assert file format type
 #   assert:
 #     that:
 #       - "'{{ format_msg_type }}' in result.stdout"
 
-- name: update database table employee
+- name: Dump and Import | Update database table employee
   command: "{{ mysql_command }} {{ db_name }} \"-e update employee set name='John Doe' where id=47\""
 
-- name: test state=import to restore the database of type {{ format_type }} (expect changed=true)
+- name: Dump and Import | Test state=import to restore the database of type {{ format_type }} (expect changed=true)
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name }}'
     state: import
     target: '{{ db_file_name }}'
   register: result
 
-- name: assert output message restore the database
+- name: Dump and Import | Assert output message restore the database
   assert:
     that:
       - result is changed
 
-- name: select data from table employee
+- name: Dump and Import | Select data from table employee
   command: "{{ mysql_command }} {{ db_name }} \"-e select * from  employee\""
   register: result
 
-- name: assert data in database is from the restore database
+- name: Dump and Import | Assert data in database is from the restore database
   assert:
     that:
       - "'47' in result.stdout"
@@ -380,14 +383,14 @@
 # Test ``force`` parameter
 ##########################
 
-- name: create wrong sql file
+- name: Dump and Import | Create wrong sql file
   shell: echo 'CREATE TABLE hello (id int); CREATE ELBAT ehlo (int id);' >> '{{ wrong_sql_file }}'
 
-- name: try to import without force parameter, must fail
+- name: Dump and Import | Try to import without force parameter, must fail
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name }}'
     state: import
@@ -400,11 +403,11 @@
     that:
       - result is failed
 
-- name: try to import with force parameter
+- name: Dump and Import | Try to import with force parameter
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name }}'
     state: import
@@ -420,40 +423,24 @@
 # Clean up
 ##########
 
-- name: remove database name
+- name: Dump and Import | Clean up databases
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
-    name: '{{ db_name }}'
+    name: '{{ item }}'
     state: absent
+  loop:
+    - '{{ db_name }}'
+    - '{{ db_name2 }}'
 
-- name: remove database
-  mysql_db:
-    login_user: '{{ mysql_user }}'
-    login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
-    login_port: '{{ mysql_primary_port }}'
-    name: '{{ db_name2 }}'
-    state: absent
-
-- name: remove file name
+- name: Dump and Import | Clean up files
   file:
-    name: '{{ db_file_name }}'
-    state: absent
-
-- name: remove file name
-  file:
-    name: '{{ wrong_sql_file }}'
-    state: absent
-
-- name: remove dump file1
-  file:
-    name: '{{ dump_file1 }}'
-    state: absent
-
-- name: remove dump file2
-  file:
-    name: '{{ dump_file2 }}'
+    name: '{{ item }}'
     state: absent
+  loop:
+    - '{{ db_file_name }}'
+    - '{{ wrong_sql_file }}'
+    - '{{ dump_file1 }}'
+    - '{{ dump_file2 }}'
diff --git a/tests/integration/targets/test_mysql_db/tasks/state_present_absent.yml b/tests/integration/targets/test_mysql_db/tasks/state_present_absent.yml
index 5b6e871..12633f2 100644
--- a/tests/integration/targets/test_mysql_db/tasks/state_present_absent.yml
+++ b/tests/integration/targets/test_mysql_db/tasks/state_present_absent.yml
@@ -1,3 +1,4 @@
+---
 # test code for mysql_db module with database name containing special chars
 
 # This file is part of Ansible
@@ -16,75 +17,75 @@
 # along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
 
 # ============================================================
-- name: remove database if it exists
+- name: State Present Absent | Remove database if it exists
   command: >
     "{{ mysql_command }} -sse 'DROP DATABASE IF EXISTS {{ db_name }}'"
   ignore_errors: true
 
-- name: make sure the test database is not there
+- name: State Present Absent | Make sure the test database is not there
   command: "{{ mysql_command }} {{ db_name }}"
   register: mysql_db_check
   failed_when: "'1049' not in mysql_db_check.stderr"
 
-- name: test state=present for a database name (expect changed=true)
+- name: State Present Absent | Test state=present for a database name (expect changed=true)
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name }}'
     state: present
   register: result
 
-- name: assert output message that database exist
+- name: State Present Absent | Assert output message that database exist
   assert:
     that:
       - result is changed
       - result.db == '{{ db_name }}'
       - result.executed_commands == ["CREATE DATABASE `{{ db_name }}`"]
 
-- name: run command to test state=present for a database name (expect db_name in stdout)
+- name: State Present Absent | Run command to test state=present for a database name (expect db_name in stdout)
   command: "{{ mysql_command }} -e \"show databases like '{{ db_name | regex_replace(\"([%_\\\\])\", \"\\\\\\1\") }}'\""
   register: result
 
-- name: assert database exist
+- name: State Present Absent | Assert database exist
   assert:
     that:
       - "'{{ db_name }}' in result.stdout"
 
 # ============================================================
-- name: test state=absent for a database name (expect changed=true)
+- name: State Present Absent | Test state=absent for a database name (expect changed=true)
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_name }}'
     state: absent
   register: result
 
-- name: assert output message that database does not exist
+- name: State Present Absent | Assert output message that database does not exist
   assert:
     that:
       - result is changed
       - result.db == '{{ db_name }}'
       - result.executed_commands == ["DROP DATABASE `{{ db_name }}`"]
 
-- name: run command to test state=absent for a database name (expect db_name not in stdout)
+- name: State Present Absent | Run command to test state=absent for a database name (expect db_name not in stdout)
   command: "{{ mysql_command }} -e \"show databases like '{{ db_name | regex_replace(\"([%_\\\\])\", \"\\\\\\1\") }}'\""
   register: result
 
-- name: assert database does not exist
+- name: State Present Absent | Assert database does not exist
   assert:
     that:
       - "'{{ db_name }}' not in result.stdout"
 
 # ============================================================
-- name: test mysql_db encoding param not valid - issue 8075
+- name: State Present Absent | Test mysql_db encoding param not valid - issue 8075
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: datanotvalid
     state: present
@@ -92,7 +93,7 @@
   register: result
   ignore_errors: true
 
-- name: assert test mysql_db encoding param not valid - issue 8075 (failed=true)
+- name: State Present Absent | Assert test mysql_db encoding param not valid - issue 8075 (failed=true)
   assert:
     that:
       - result is failed
@@ -100,201 +101,202 @@
       - "'Unknown character set' in result.msg"
 
 # ============================================================
-- name: test mysql_db using a valid encoding utf8 (expect changed=true)
+- name: State Present Absent | Test mysql_db using a valid encoding utf8 (expect changed=true)
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: 'en{{ db_name }}'
     state: present
     encoding: utf8
   register: result
 
-- name: assert output message created a database
+- name: State Present Absent | Assert output message created a database
   assert:
     that:
       - result is changed
       - result.executed_commands == ["CREATE DATABASE `en{{ db_name }}` CHARACTER SET 'utf8'"]
 
-- name: test database was created
+- name: State Present Absent | Test database was created
   command: "{{ mysql_command }} -e \"SHOW CREATE DATABASE `en{{ db_name }}`\""
   register: result
 
-- name: assert created database is of encoding utf8
+- name: State Present Absent | Assert created database is of encoding utf8
   assert:
     that:
       - "'utf8' in result.stdout"
 
-- name: remove database
+- name: State Present Absent | Remove database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: 'en{{ db_name }}'
     state: absent
 
 # ============================================================
-- name: test mysql_db using valid encoding binary (expect changed=true)
+- name: State Present Absent | Test mysql_db using valid encoding binary (expect changed=true)
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: 'en{{ db_name }}'
     state: present
     encoding: binary
   register: result
 
-- name: assert output message that database was created
+- name: State Present Absent | Assert output message that database was created
   assert:
     that:
       - result is changed
       - result.executed_commands == ["CREATE DATABASE `en{{ db_name }}` CHARACTER SET 'binary'"]
 
-- name: run command to test database was created
+- name: State Present Absent | Run command to test database was created
   command: "{{ mysql_command }} -e \"SHOW CREATE DATABASE `en{{ db_name }}`\""
   register: result
 
-- name: assert created database is of encoding binary
+- name: State Present Absent | Assert created database is of encoding binary
   assert:
     that:
       - "'binary' in result.stdout"
 
-- name: remove database
+- name: State Present Absent | Remove database
   mysql_db:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: 'en{{ db_name }}'
     state: absent
 
 # ============================================================
-- name: create user1 to access database dbuser1
+- name: State Present Absent | Create user1 to access database dbuser1
   mysql_user:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: user1
+    host: '%'
     password: 'Hfd6fds^dfA8Ga'
     priv: '*.*:ALL'
     state: present
 
-- name: create database dbuser1 using user1
+- name: State Present Absent | Create database dbuser1 using user1
   mysql_db:
     login_user: user1
     login_password: 'Hfd6fds^dfA8Ga'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_user1 }}'
     state: present
   register: result
 
-- name: assert output message that database was created
+- name: State Present Absent | Assert output message that database was created
   assert:
     that:
       - result is changed
 
-- name: run command to test database was created using user1
+- name: State Present Absent | Run command to test database was created using user1
   command: "{{ mysql_command }} -e \"show databases like '{{ db_user1 | regex_replace(\"([%_\\\\])\", \"\\\\\\1\") }}'\""
   register: result
 
-- name: assert database exist
+- name: State Present Absent | Assert database exist
   assert:
     that:
       - "'{{ db_user1 }}' in result.stdout"
 
 # ============================================================
-- name: create user2 to access database with privilege select only
+- name: State Present Absent | Create user2 to access database with privilege select only
   mysql_user:
     login_user: '{{ mysql_user }}'
     login_password: '{{ mysql_password }}'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: user2
     password: 'kjsfd&F7safjad'
     priv: '*.*:SELECT'
     state: present
 
-- name: create database dbuser2 using user2 with no privilege to create (expect failed=true)
+- name: State Present Absent | Create database dbuser2 using user2 with no privilege to create (expect failed=true)
   mysql_db:
     login_user: user2
     login_password: 'kjsfd&F7safjad'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_user2 }}'
     state: present
   register: result
   ignore_errors: true
 
-- name: assert output message that database was not created using dbuser2
+- name: State Present Absent | Assert output message that database was not created using dbuser2
   assert:
     that:
       - result is failed
       - "'Access denied' in result.msg"
 
-- name: run command to test that database was not created
+- name: State Present Absent | Run command to test that database was not created
   command: "{{ mysql_command }} -e \"show databases like '{{ db_user2 | regex_replace(\"([%_\\\\])\", \"\\\\\\1\") }}'\""
   register: result
 
-- name: assert database does not exist
+- name: State Present Absent | Assert database does not exist
   assert:
     that:
       - "'{{ db_user2 }}' not in result.stdout"
 
 # ============================================================
-- name: delete database using user2 with no privilege to delete (expect failed=true)
+- name: State Present Absent | Delete database using user2 with no privilege to delete (expect failed=true)
   mysql_db:
     login_user: user2
     login_password: 'kjsfd&F7safjad'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_user1 }}'
     state: absent
   register: result
   ignore_errors: true
 
-- name: assert output message that database was not deleted using dbuser2
+- name: State Present Absent | Assert output message that database was not deleted using dbuser2
   assert:
     that:
       - result is failed
       - "'Access denied' in result.msg"
 
-- name: run command to test database was not deleted
+- name: State Present Absent | Run command to test database was not deleted
   command: "{{ mysql_command }} -e \"show databases like '{{ db_user1 | regex_replace(\"([%_\\\\])\", \"\\\\\\1\") }}'\""
   register: result
 
-- name: assert database still exist
+- name: State Present Absent | Assert database still exist
   assert:
     that:
       - "'{{ db_user1 }}' in result.stdout"
 
 # ============================================================
-- name: delete database using user1 with all privilege to delete a database (expect changed=true)
+- name: State Present Absent | Delete database using user1 with all privilege to delete a database (expect changed=true)
   mysql_db:
     login_user: user1
     login_password: 'Hfd6fds^dfA8Ga'
-    login_host: 127.0.0.1
+    login_host: '{{ mysql_host }}'
     login_port: '{{ mysql_primary_port }}'
     name: '{{ db_user1 }}'
     state: absent
   register: result
   ignore_errors: true
 
-- name: assert output message that database was deleted using user1
+- name: State Present Absent | Assert output message that database was deleted using user1
   assert:
     that:
       - result is changed
       - result.executed_commands == ["DROP DATABASE `{{ db_user1 }}`"]
 
-- name: run command to test database was deleted using user1
+- name: State Present Absent | Run command to test database was deleted using user1
   command: "{{ mysql_command }} -e \"show databases like '{{ db_name | regex_replace(\"([%_\\\\])\", \"\\\\\\1\") }}'\""
   register: result
 
-- name: assert database does not exist
+- name: State Present Absent | Assert database does not exist
   assert:
     that:
       - "'{{ db_user1 }}' not in result.stdout"
diff --git a/tests/integration/targets/test_mysql_info/defaults/main.yml b/tests/integration/targets/test_mysql_info/defaults/main.yml
index e1b932c..e1cd880 100644
--- a/tests/integration/targets/test_mysql_info/defaults/main.yml
+++ b/tests/integration/targets/test_mysql_info/defaults/main.yml
@@ -2,7 +2,7 @@
 # defaults file for test_mysql_info
 mysql_user: root
 mysql_password: msandbox
-mysql_host: 127.0.0.1
+mysql_host: '{{ gateway_addr }}'
 mysql_primary_port: 3307
 
 db_name: data
diff --git a/tests/integration/targets/test_mysql_info/meta/main.yml b/tests/integration/targets/test_mysql_info/meta/main.yml
index a7ace5d..4be5f58 100644
--- a/tests/integration/targets/test_mysql_info/meta/main.yml
+++ b/tests/integration/targets/test_mysql_info/meta/main.yml
@@ -1,3 +1,4 @@
+---
 dependencies:
-  - setup_mysql
+  - setup_controller
   - setup_remote_tmp_dir
diff --git a/tests/integration/targets/test_mysql_info/tasks/connector_info.yml b/tests/integration/targets/test_mysql_info/tasks/connector_info.yml
index 349ccef..f7890b0 100644
--- a/tests/integration/targets/test_mysql_info/tasks/connector_info.yml
+++ b/tests/integration/targets/test_mysql_info/tasks/connector_info.yml
@@ -2,7 +2,6 @@
 # Added in 1.5.0, 2.4.0 and 3.6.0 in
 # https://github.com/ansible-collections/community.mysql/pull/497
 
-# TODO: Refactor in PR490.
 - name: Connector info | Assert connector_name exists and has expected values
   ansible.builtin.assert:
     that:
@@ -15,18 +14,17 @@
       {{ result.connector_name | d('Unknown')}} which is different than expected
       pymysql or MySQLdb
 
-# TODO: Refactor in PR490.
 - name: Connector info | Assert connector_version exists and has expected values
   ansible.builtin.assert:
     that:
       - result.connector_version is defined
       - >
         result.connector_version == 'Unknown'
-        or result.connector_version is version(connector_ver, '==')
+        or result.connector_version is version(connector_version, '==')
     success_msg: >-
       Assertions passed, result.connector_version is
       {{ result.connector_version }}
     fail_msg: >-
       Assertion failed, result.connector_version is
       {{ result.connector_version }} which is different than expected
-      {{ connector_ver }}
+      {{ connector_version }}
diff --git a/tests/integration/targets/test_mysql_info/tasks/issue-28.yml b/tests/integration/targets/test_mysql_info/tasks/issue-28.yml
index 068fbb3..1fbf3a9 100644
--- a/tests/integration/targets/test_mysql_info/tasks/issue-28.yml
+++ b/tests/integration/targets/test_mysql_info/tasks/issue-28.yml
@@ -1,7 +1,4 @@
 ---
-- name: alias mysql command to include default options
-  set_fact:
-    mysql_command: "mysql -u{{ mysql_user }} -p{{ mysql_password }} -P{{ mysql_primary_port }} --protocol=tcp"
 
 - name: set fact tls_enabled
   command: "{{ mysql_command }} \"-e SHOW VARIABLES LIKE 'have_ssl';\""
@@ -13,7 +10,7 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
   when: tls_enabled
   block:
@@ -30,6 +27,7 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
+        host_all: true
         state: absent
       ignore_errors: yes
 
@@ -37,6 +35,7 @@
       mysql_user:
         <<: *mysql_params
         name: "{{ user_name_1 }}"
+        host: "%"
         password: "{{ user_password_1 }}"
         tls_requires:
           SSL:
@@ -46,7 +45,7 @@
         filter: version
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
       register: result
@@ -55,19 +54,21 @@
     - assert:
         that:
           - result is failed
-      when: connector_name is search('pymysql')
+      when:
+        - connector_name == 'pymysql'
 
     - assert:
         that:
           - result is succeeded
-      when: connector_name is not search('pymysql')
+      when:
+        - connector_name != 'pymysql'
 
     - name: attempt connection with newly created user ignoring hostname
       mysql_info:
         filter: version
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
         check_hostname: no
@@ -82,5 +83,5 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
-        host: 127.0.0.1
+        host_all: true
         state: absent
diff --git a/tests/integration/targets/test_mysql_info/tasks/main.yml b/tests/integration/targets/test_mysql_info/tasks/main.yml
index a5428e3..a01f915 100644
--- a/tests/integration/targets/test_mysql_info/tasks/main.yml
+++ b/tests/integration/targets/test_mysql_info/tasks/main.yml
@@ -1,3 +1,4 @@
+---
 ####################################################################
 # WARNING: These are designed specifically for Ansible tests       #
 # and should not be used as examples of how to write Ansible roles #
@@ -24,14 +25,14 @@
     - name: mysql_info - create default config file
       template:
         src: my.cnf.j2
-        dest: /root/.my.cnf
+        dest: "{{ playbook_dir }}/root/.my.cnf"
         mode: '0400'
 
     # Create non-default MySQL config file with credentials
     - name: mysql_info - create non-default config file
       template:
         src: my.cnf.j2
-        dest: /root/non-default_my.cnf
+        dest: "{{ playbook_dir }}/root/non-default_my.cnf"
         mode: '0400'
 
     ###############
@@ -43,17 +44,18 @@
         login_user: '{{ mysql_user }}'
         login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
+        config_file: "{{ playbook_dir }}/root/.my.cnf"
       register: result
 
     - assert:
         that:
-        - result is not changed
-        - "mysql_version in result.version.full or mariadb_version in result.version.full"
-        - result.settings != {}
-        - result.global_status != {}
-        - result.databases != {}
-        - result.engines != {}
-        - result.users != {}
+          - result is not changed
+          - db_version in result.version.full
+          - result.settings != {}
+          - result.global_status != {}
+          - result.databases != {}
+          - result.engines != {}
+          - result.users != {}
 
     - name: mysql_info - Test connector informations display
       ansible.builtin.import_tasks:
@@ -65,7 +67,7 @@
         login_user: '{{ mysql_user }}'
         login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
-        config_file: /root/non-default_my.cnf
+        config_file: "{{ playbook_dir }}/root/non-default_my.cnf"
       register: result
 
     - assert:
@@ -78,9 +80,9 @@
       file:
         path: '{{ item }}'
         state: absent
-      with_items:
-      - /root/.my.cnf
-      - /root/non-default_my.cnf
+      loop:
+        - "{{ playbook_dir }}/.my.cnf"
+        - "{{ playbook_dir }}/non-default_my.cnf"
 
     # Access with password
     - name: mysql_info - check access with password
diff --git a/tests/integration/targets/test_mysql_query/defaults/main.yml b/tests/integration/targets/test_mysql_query/defaults/main.yml
index 4ee25ff..6befdcf 100644
--- a/tests/integration/targets/test_mysql_query/defaults/main.yml
+++ b/tests/integration/targets/test_mysql_query/defaults/main.yml
@@ -1,5 +1,6 @@
 mysql_user: root
 mysql_password: msandbox
+mysql_host: '{{ gateway_addr }}'
 mysql_primary_port: 3307
 
 db_name: data
diff --git a/tests/integration/targets/test_mysql_query/meta/main.yml b/tests/integration/targets/test_mysql_query/meta/main.yml
index ce08dc4..01ee3db 100644
--- a/tests/integration/targets/test_mysql_query/meta/main.yml
+++ b/tests/integration/targets/test_mysql_query/meta/main.yml
@@ -1,2 +1,3 @@
+---
 dependencies:
-- setup_mysql
+  - setup_controller
diff --git a/tests/integration/targets/test_mysql_query/tasks/issue-28.yml b/tests/integration/targets/test_mysql_query/tasks/issue-28.yml
index 43eda1a..f7d8ba1 100644
--- a/tests/integration/targets/test_mysql_query/tasks/issue-28.yml
+++ b/tests/integration/targets/test_mysql_query/tasks/issue-28.yml
@@ -1,7 +1,4 @@
 ---
-- name: alias mysql command to include default options
-  set_fact:
-    mysql_command: "mysql -u{{ mysql_user }} -p{{ mysql_password }} -P{{ mysql_primary_port }} --protocol=tcp"
 
 - name: set fact tls_enabled
   command: "{{ mysql_command }} \"-e SHOW VARIABLES LIKE 'have_ssl';\""
@@ -13,7 +10,7 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
   when: tls_enabled
   block:
@@ -30,6 +27,7 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
+        host_all: true
         state: absent
       ignore_errors: yes
 
@@ -37,6 +35,7 @@
       mysql_user:
         <<: *mysql_params
         name: "{{ user_name_1 }}"
+        host: "%"
         password: "{{ user_password_1 }}"
         tls_requires:
           SSL:
@@ -46,7 +45,7 @@
         query: 'SHOW DATABASES'
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
       register: result
@@ -55,19 +54,21 @@
     - assert:
         that:
           - result is failed
-      when: connector_name is search('pymysql')
+      when:
+        - connector_name == 'pymysql'
 
     - assert:
         that:
           - result is succeeded
-      when: connector_name is not search('pymysql')
+      when:
+        - connector_name != 'pymysql'
 
     - name: attempt connection with newly created user ignoring hostname
       mysql_query:
         query: 'SHOW DATABASES'
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
         check_hostname: no
@@ -82,5 +83,5 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
-        host: 127.0.0.1
+        host: "%"
         state: absent
diff --git a/tests/integration/targets/test_mysql_query/tasks/mysql_query_initial.yml b/tests/integration/targets/test_mysql_query/tasks/mysql_query_initial.yml
index cbb7b53..d97c554 100644
--- a/tests/integration/targets/test_mysql_query/tasks/mysql_query_initial.yml
+++ b/tests/integration/targets/test_mysql_query/tasks/mysql_query_initial.yml
@@ -1,3 +1,4 @@
+---
 # Test code for mysql_query module
 # Copyright: (c) 2020, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -5,7 +6,7 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
@@ -16,7 +17,8 @@
       query: 'CREATE DATABASE {{ test_db }}'
     register: result
 
-  - assert:
+  - name: Assert that create db test_db is changed and returns expected query
+    assert:
       that:
         - result is changed
         - result.executed_queries == ['CREATE DATABASE {{ test_db }}']
@@ -28,7 +30,8 @@
       query: 'CREATE TABLE {{ test_table1 }} (id int)'
     register: result
 
-  - assert:
+  - name: Assert that create table test_table1 is changed and returns expected query
+    assert:
       that:
         - result is changed
         - result.executed_queries == ['CREATE TABLE {{ test_table1 }} (id int)']
@@ -38,12 +41,13 @@
       <<: *mysql_params
       login_db: '{{ test_db }}'
       query:
-      - 'INSERT INTO {{ test_table1 }} VALUES (1), (2)'
-      - 'INSERT INTO {{ test_table1 }} VALUES (3)'
+        - 'INSERT INTO {{ test_table1 }} VALUES (1), (2)'
+        - 'INSERT INTO {{ test_table1 }} VALUES (3)'
       single_transaction: yes
     register: result
 
-  - assert:
+  - name: Assert that inserting test data is changed and returns expected query and results
+    assert:
       that:
         - result is changed
         - result.rowcount == [2, 1]
@@ -56,7 +60,8 @@
       query: 'SELECT * FROM {{ test_table1 }}'
     register: result
 
-  - assert:
+  - name: Assert that query data in test_table1 is not changed and returns expected query and results
+    assert:
       that:
         - result is not changed
         - result.executed_queries == ['SELECT * FROM {{ test_table1 }}']
@@ -74,7 +79,8 @@
       - 1
     register: result
 
-  - assert:
+  - name: Assert that query data in test_table1 using positional args is not changed and returns expected query and results
+    assert:
       that:
         - result is not changed
         - result.executed_queries == ["SELECT * FROM {{ test_table1 }} WHERE id = 1"]
@@ -90,7 +96,8 @@
         some_id: 1
     register: result
 
-  - assert:
+  - name: Assert that query data in test_table1 using named args is not changed and returns expected query and results
+    assert:
       that:
         - result is not changed
         - result.executed_queries == ["SELECT * FROM {{ test_table1 }} WHERE id = 1"]
@@ -107,7 +114,8 @@
         new_id: 0
     register: result
 
-  - assert:
+  - name: Assert that update data in test_table1 is changed and returns the expected query
+    assert:
       that:
         - result is changed
         - result.executed_queries == ['UPDATE {{ test_table1 }} SET id = 0 WHERE id = 1']
@@ -122,7 +130,8 @@
         some_id: 1
     register: result
 
-  - assert:
+  - name: Assert that query that check the prev update is not changed and returns the expected query with id = 1
+    assert:
       that:
         - result is not changed
         - result.executed_queries == ['SELECT * FROM {{ test_table1 }} WHERE id = 1']
@@ -137,7 +146,8 @@
         some_id: 0
     register: result
 
-  - assert:
+  - name: Assert that query that check the prev update is not changed and returns the expected query with id = 0
+    assert:
       that:
         - result is not changed
         - result.executed_queries == ['SELECT * FROM {{ test_table1 }} WHERE id = 0']
@@ -153,7 +163,8 @@
         new_id: 0
     register: result
 
-  - assert:
+  - name: Assert that update data in test_table1 again is not changed and returns expected query
+    assert:
       that:
         - result is not changed
         - result.executed_queries == ['UPDATE {{ test_table1 }} SET id = 0 WHERE id = 1']
@@ -168,7 +179,8 @@
       - 'SELECT * FROM {{ test_table1 }} WHERE id = 0'
     register: result
 
-  - assert:
+  - name: Assert that delete data from test_table1 is changed an returns expected query
+    assert:
       that:
         - result is changed
         - result.executed_queries == ['DELETE FROM {{ test_table1 }} WHERE id = 0', 'SELECT * FROM {{ test_table1 }} WHERE id = 0']
@@ -181,7 +193,8 @@
       query: 'DELETE FROM {{ test_table1 }} WHERE id = 0'
     register: result
 
-  - assert:
+  - name: Assert that delete data from test_table1 again is not changed and returns expected query
+    assert:
       that:
         - result is not changed
         - result.executed_queries == ['DELETE FROM {{ test_table1 }} WHERE id = 0']
@@ -192,11 +205,12 @@
       <<: *mysql_params
       login_db: '{{ test_db }}'
       query:
-      - 'TRUNCATE {{ test_table1 }}'
-      - 'SELECT * FROM {{ test_table1 }}'
+        - 'TRUNCATE {{ test_table1 }}'
+        - 'SELECT * FROM {{ test_table1 }}'
     register: result
 
-  - assert:
+  - name: Assert that truncate test_table1 is changed and returns expected query
+    assert:
       that:
         - result is changed
         - result.executed_queries == ['TRUNCATE {{ test_table1 }}', 'SELECT * FROM {{ test_table1 }}']
@@ -209,7 +223,8 @@
       query: 'RENAME TABLE {{ test_table1 }} TO {{ test_table2 }}'
     register: result
 
-  - assert:
+  - name: Assert that rename table test_table1 is changed and returns expected query
+    assert:
       that:
         - result is changed
         - result.executed_queries == ['RENAME TABLE {{ test_table1 }} TO {{ test_table2 }}']
@@ -223,7 +238,8 @@
     register: result
     ignore_errors: yes
 
-  - assert:
+  - name: Assert that query old table is failed
+    assert:
       that:
         - result is failed
 
@@ -234,7 +250,8 @@
       query: 'SELECT * FROM {{ test_table2 }}'
     register: result
 
-  - assert:
+  - name: Assert that query new table succeed and returns 0 row
+    assert:
       that:
         - result.rowcount == [0]
 
@@ -257,7 +274,8 @@
       query: 'SELECT id, story FROM {{ test_table3 }}'
     register: result
 
-  - assert:
+  - name: Assert that select from test_table3 returns 2 rows
+    assert:
       that:
         - result.rowcount == [2]
 
@@ -269,7 +287,8 @@
     register: result
     ignore_errors: yes
 
-  - assert:
+  - name: Assert that pass wrong query type is failed
+    assert:
       that:
         - result is failed
         - result.msg is search('the query option value must be a string or list')
@@ -284,7 +303,8 @@
     register: result
     ignore_errors: yes
 
-  - assert:
+  - name: Assert that pass wrong query element is failed
+    assert:
       that:
         - result is failed
         - result.msg is search('the elements in query list must be strings')
@@ -303,7 +323,8 @@
       single_transaction: yes
     register: result
 
-  - assert:
+  - name: Assert that insert test data using replace statement is changed
+    assert:
       that:
         - result is changed
         - result.rowcount == [1]
@@ -339,20 +360,24 @@
     register: result
 
   # Issue https://github.com/ansible-collections/community.mysql/issues/268
-  - assert:
+  - name: Assert that create table IF NOT EXISTS is not changed with pymysql
+    assert:
       that:
         # PyMySQL driver throws a warning, so the following is correct
         - result is not changed
-    when: connector_name is search('pymysql')
+    when:
+      - connector_name == 'pymysql'
 
   # Issue https://github.com/ansible-collections/community.mysql/issues/268
-  - assert:
+  - name: Assert that create table IF NOT EXISTS is changed with mysqlclient
+    assert:
       that:
-        # mysqlclient driver throws nothing, so it's impossible to figure out
-        # if the state was changed or not.
-        # We assume that it was for DDL queryes by default in the code
+        # Mysqlclient 2.0.1, driver throws nothing with mysql, so it's
+        # impossible to figure out  if the state was changed or not.
+        # We assume that it was for DDL queries by default in the code
         - result is changed
-    when: connector_name is search('mysqlclient')
+    when:
+      - connector_name == 'mysqlclient'
 
   - name: Drop db {{ test_db }}
     mysql_query:
@@ -360,7 +385,15 @@
       query: 'DROP DATABASE {{ test_db }}'
     register: result
 
-  - assert:
+  - name: Assert that drop database is changed and returns expected query
+    assert:
       that:
         - result is changed
         - result.executed_queries == ['DROP DATABASE {{ test_db }}']
+
+  always:
+
+    - name: Clean up test_db
+      mysql_query:
+        <<: *mysql_params
+        query: 'DROP DATABASE IF EXISTS {{ test_db }}'
diff --git a/tests/integration/targets/test_mysql_replication/defaults/main.yml b/tests/integration/targets/test_mysql_replication/defaults/main.yml
index fefcf29..192a151 100644
--- a/tests/integration/targets/test_mysql_replication/defaults/main.yml
+++ b/tests/integration/targets/test_mysql_replication/defaults/main.yml
@@ -1,6 +1,6 @@
 mysql_user: root
 mysql_password: msandbox
-mysql_host: 127.0.0.1
+mysql_host: '{{ gateway_addr }}'
 mysql_primary_port: 3307
 mysql_replica1_port: 3308
 mysql_replica2_port: 3309
diff --git a/tests/integration/targets/test_mysql_replication/meta/main.yml b/tests/integration/targets/test_mysql_replication/meta/main.yml
index 36e111c..01ee3db 100644
--- a/tests/integration/targets/test_mysql_replication/meta/main.yml
+++ b/tests/integration/targets/test_mysql_replication/meta/main.yml
@@ -1,3 +1,3 @@
 ---
 dependencies:
-- setup_mysql
+  - setup_controller
diff --git a/tests/integration/targets/test_mysql_replication/tasks/issue-265.yml b/tests/integration/targets/test_mysql_replication/tasks/issue-265.yml
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration/targets/test_mysql_replication/tasks/issue-28.yml b/tests/integration/targets/test_mysql_replication/tasks/issue-28.yml
index da607ce..ea17f35 100644
--- a/tests/integration/targets/test_mysql_replication/tasks/issue-28.yml
+++ b/tests/integration/targets/test_mysql_replication/tasks/issue-28.yml
@@ -1,7 +1,4 @@
 ---
-- name: alias mysql command to include default options
-  set_fact:
-    mysql_command: "mysql -u{{ mysql_user }} -p{{ mysql_password }} -P{{ mysql_primary_port }} --protocol=tcp"
 
 - name: set fact tls_enabled
   command: "{{ mysql_command }} \"-e SHOW VARIABLES LIKE 'have_ssl';\""
@@ -13,7 +10,7 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
   when: tls_enabled
   block:
@@ -30,6 +27,7 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
+        host_all: true
         state: absent
       ignore_errors: yes
 
@@ -47,7 +45,7 @@
         mode: getmaster
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
       register: result
@@ -56,19 +54,21 @@
     - assert:
         that:
           - result is failed
-      when: connector_name is search('pymysql')
+      when:
+        - connector_name == 'pymysql'
 
     - assert:
         that:
           - result is succeeded
-      when: connector_name is not search('pymysql')
+      when:
+        - connector_name != 'pymysql'
 
     - name: attempt connection with newly created user ignoring hostname
       mysql_replication:
         mode: getmaster
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
         check_hostname: no
@@ -83,5 +83,5 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
-        host: 127.0.0.1
+        host: '{{ gateway_addr }}'
         state: absent
diff --git a/tests/integration/targets/test_mysql_replication/tasks/main.yml b/tests/integration/targets/test_mysql_replication/tasks/main.yml
index eae58c0..491db34 100644
--- a/tests/integration/targets/test_mysql_replication/tasks/main.yml
+++ b/tests/integration/targets/test_mysql_replication/tasks/main.yml
@@ -15,7 +15,8 @@
 # Tests of channel parameter:
 - import_tasks: mysql_replication_channel.yml
   when:
-    - install_type == 'mysql' # FIXME: mariadb introduces FOR CHANNEL in 10.7
+    - db_engine == 'mysql' # FIXME: mariadb introduces FOR CHANNEL in 10.7
+    - mysql8022_and_higher == true  # FIXME: mysql 5.7 should work, but our tets fails, why?
 
 # Tests of resetmaster mode:
 - import_tasks: mysql_replication_resetmaster_mode.yml
diff --git a/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml b/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml
index 1bbc1bc..76ab423 100644
--- a/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml
+++ b/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_channel.yml
@@ -1,3 +1,4 @@
+---
 # Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
 
@@ -5,7 +6,7 @@
     mysql_params: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
 
   block:
     # Get master log file and log pos:
diff --git a/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml b/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml
index 7899e1a..38169ae 100644
--- a/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml
+++ b/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_initial.yml
@@ -1,3 +1,4 @@
+---
 # Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
 
@@ -5,16 +6,9 @@
     mysql_params: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
 
   block:
-    - name: find out the database version
-      mysql_info:
-        <<: *mysql_params
-        login_port: '{{ mysql_primary_port }}'
-        filter: version
-      register: db
-
     - name: Set mysql8022_and_higher
       set_fact:
         mysql8022_and_higher: false
@@ -23,21 +17,31 @@
       set_fact:
         mysql8022_and_higher: true
       when:
-      - db.version.major > 8 or (db.version.major == 8 and db.version.minor > 0) or (db.version.major == 8 and db.version.minor == 0 and db.version.release >= 22)
-      - install_type == 'mysql'
+        - db_engine == 'mysql'
+        - db_version is version('8.0.22', '>=')
 
-    - name: alias mysql command to include default options
-      set_fact:
-        mysql_command: "mysql -u{{ mysql_user }} -p{{ mysql_password }} --protocol=tcp"
-
-    # Preparation:
+    # We use iF NOT EXISTS because the GITHUB Action:
+    # "ansible-community/ansible-test-gh-action" uses "--retry-on-error".
+    # If test_mysql_replication fails, test will run again an without the IF
+    # NOT EXISTS, we see "Error 1396 (HY000): Operation CREATE USER failed..."
+    # which is misleading.
     - name: Create user for mysql replication
-      shell: "echo \"CREATE USER '{{ replication_user }}'@'localhost' IDENTIFIED WITH mysql_native_password BY '{{ replication_pass }}'; GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'localhost';\" | {{ mysql_command }} -P{{ mysql_primary_port }}"
-      when: install_type == 'mysql'
+      shell:
+        "echo \"CREATE USER IF NOT EXISTS \
+        '{{ replication_user }}'@'{{ mysql_host }}' \
+        IDENTIFIED WITH mysql_native_password BY '{{ replication_pass }}'; \
+        GRANT REPLICATION SLAVE ON *.* TO \
+        '{{ replication_user }}'@'{{ mysql_host }}';\" | {{ mysql_command }}"
+      when: db_engine == 'mysql'
 
     - name: Create user for mariadb replication
-      shell: "echo \"CREATE USER '{{ replication_user }}'@'localhost' IDENTIFIED BY '{{ replication_pass }}'; GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'localhost';\" | {{ mysql_command }} -P{{ mysql_primary_port }}"
-      when: install_type == 'mariadb'
+      shell:
+        "echo \"CREATE USER IF NOT EXISTS \
+        '{{ replication_user }}'@'{{ mysql_host }}' \
+        IDENTIFIED BY '{{ replication_pass }}'; \
+        GRANT REPLICATION SLAVE ON *.* TO \
+        '{{ replication_user }}'@'{{ mysql_host }}';\" | {{ mysql_command }}"
+      when: db_engine == 'mariadb'
 
     - name: Create test database
       mysql_db:
@@ -47,13 +51,31 @@
         name: '{{ test_db }}'
 
     - name: Dump all databases from the primary
-      shell: 'mysqldump -u{{ mysql_user }} -p{{ mysql_password }} -h{{ mysql_host }} --protocol=tcp -P{{ mysql_primary_port }} --all-databases --ignore-table=mysql.innodb_index_stats --ignore-table=mysql.innodb_table_stats --master-data=2 > {{ dump_path }}'
+      shell:
+        cmd: >-
+          mysqldump
+          -u{{ mysql_user }}
+          -p{{ mysql_password }}
+          -h{{ mysql_host }}
+          -P{{ mysql_primary_port }}
+          --protocol=tcp
+          --all-databases
+          --ignore-table=mysql.innodb_index_stats
+          --ignore-table=mysql.innodb_table_stats
+          --master-data=2
+          > {{ dump_path }}
 
     - name: Restore the dump to replica1
-      shell: '{{ mysql_command }} -P{{ mysql_replica1_port }} < {{ dump_path }}'
+      shell:
+        cmd: >-
+          {{ mysql_command_wo_port }}
+          -P{{ mysql_replica1_port }} < {{ dump_path }}
 
     - name: Restore the dump to replica2
-      shell: '{{ mysql_command }} -P{{ mysql_replica2_port }} < {{ dump_path }}'
+      shell:
+        cmd: >-
+          {{ mysql_command_wo_port }}
+          -P{{ mysql_replica2_port }} < {{ dump_path }}
 
     # Test getmaster mode:
     - name: Get master status
@@ -63,7 +85,8 @@
         mode: getmaster
       register: mysql_primary_status
 
-    - assert:
+    - name: Assert that primary is in expected state
+      assert:
         that:
         - mysql_primary_status.Is_Master == true
         - mysql_primary_status.Position != 0
@@ -79,9 +102,10 @@
       register: result
       ignore_errors: yes
 
-    - assert:
+    - name: Assert that startreplica is failed
+      assert:
         that:
-        - result is failed
+          - result is failed
 
     # Test startreplica doesn't fail if fail_on_error: no
     - name: Start replica and fail without propagating it to ansible as we were asked not to
@@ -92,9 +116,10 @@
         fail_on_error: no
       register: result
 
-    - assert:
+    - name: Assert that startreplica succeeded
+      assert:
         that:
-        - result is not failed
+          - result is not failed
 
     # Test startreplica doesn't fail if there is no fail_on_error.
     # This is suboptimal because nothing happens, but it's the old behavior.
@@ -105,9 +130,10 @@
         mode: startreplica
       register: result
 
-    - assert:
+    - name: Assert that start replica succeeded again
+      assert:
         that:
-        - result is not failed
+          - result is not failed
 
     # Test changemaster mode:
     # master_ssl_ca will be set as '' to check the module's behaviour for #23976,
@@ -126,7 +152,8 @@
         master_ssl_ca: ''
       register: result
 
-    - assert:
+    - name: Assert that changeprimmary is changed and return expected query
+      assert:
         that:
         - result is changed
         - result.queries == ["CHANGE MASTER TO MASTER_HOST='{{ mysql_host }}',MASTER_USER='{{ replication_user }}',MASTER_PASSWORD='********',MASTER_PORT={{ mysql_primary_port }},MASTER_LOG_FILE='{{ mysql_primary_status.File }}',MASTER_LOG_POS={{ mysql_primary_status.Position }},MASTER_SSL_CA=''"]
@@ -139,10 +166,11 @@
         mode: startreplica
       register: result
 
-    - assert:
+    - name: Assert that startreplica is changed and returns expected query
+      assert:
         that:
-        - result is changed
-        - result.queries == ["START SLAVE"] or result.queries == ["START REPLICA"]
+          - result is changed
+          - result.queries == ["START SLAVE"] or result.queries == ["START REPLICA"]
 
     # Test getreplica mode:
     - name: Get replica status using deprecated getslave choice
@@ -152,7 +180,8 @@
         mode: getslave
       register: replica_status
 
-    - assert:
+    - name: Assert that getreplica returns expected values for MySQL older than 8.0.22 and Mariadb
+      assert:
         that:
         - replica_status.Is_Slave == true
         - replica_status.Master_Host == '{{ mysql_host }}'
@@ -163,7 +192,8 @@
         - replica_status is not changed
       when: mysql8022_and_higher == false
 
-    - assert:
+    - name: Assert that getreplica returns expected values for MySQL newer than 8.0.22
+      assert:
         that:
         - replica_status.Is_Slave == true
         - replica_status.Source_Host == '{{ mysql_host }}'
@@ -176,10 +206,10 @@
 
     # Create test table and add data to it:
     - name: Create test table
-      shell: "echo \"CREATE TABLE {{ test_table }} (id int);\" | {{ mysql_command }} -P{{ mysql_primary_port }} {{ test_db }}"
+      shell: "echo \"CREATE TABLE {{ test_table }} (id int);\" | {{ mysql_command_wo_port }} -P{{ mysql_primary_port }} {{ test_db }}"
 
     - name: Insert data
-      shell: "echo \"INSERT INTO {{ test_table }} (id) VALUES (1), (2), (3); FLUSH LOGS;\" | {{ mysql_command }} -P{{ mysql_primary_port }} {{ test_db }}"
+      shell: "echo \"INSERT INTO {{ test_table }} (id) VALUES (1), (2), (3); FLUSH LOGS;\" | {{ mysql_command_wo_port }} -P{{ mysql_primary_port }} {{ test_db }}"
 
     - name: Small pause to be sure the bin log, which was flushed previously, reached the replica
       ansible.builtin.wait_for:
@@ -195,14 +225,16 @@
 
     # mysql_primary_status.Position is not actual and it has been changed by the prev step,
     # so replica_status.Exec_Master_Log_Pos must be different:
-    - assert:
+    - name: Assert that getreplica Log_Pos is different for MySQL older than 8.0.22 and MariaDB
+      assert:
         that:
-        - replica_status.Exec_Master_Log_Pos != mysql_primary_status.Position
+          - replica_status.Exec_Master_Log_Pos != mysql_primary_status.Position
       when: mysql8022_and_higher == false
 
-    - assert:
+    - name: Assert that getreplica Log_Pos is different for MySQL newer than 8.0.22
+      assert:
         that:
-        - replica_status.Exec_Source_Log_Pos != mysql_primary_status.Position
+          - replica_status.Exec_Source_Log_Pos != mysql_primary_status.Position
       when: mysql8022_and_higher == true
 
     - name: Start replica that is already running
@@ -214,7 +246,8 @@
       register: result
 
     # mysqlclient 2.0.1 always return "changed"
-    - assert:
+    - name: Assert that startreplica is not changed
+      assert:
         that:
           - result is not changed
       when:
@@ -228,10 +261,11 @@
         mode: stopslave
       register: result
 
-    - assert:
+    - name: Assert that stopreplica is changed and returns expected query
+      assert:
         that:
-        - result is changed
-        - result.queries == ["STOP SLAVE"] or result.queries == ["STOP REPLICA"]
+          - result is changed
+          - result.queries == ["STOP SLAVE"] or result.queries == ["STOP REPLICA"]
 
     - name: Pause for 2 seconds to let the replication stop
       ansible.builtin.wait_for:
@@ -247,7 +281,8 @@
         fail_on_error: true
       register: result
 
-    - assert:
+    - name: Assert that stopreplica is not changed
+      assert:
         that:
           - result is not changed
       when:
diff --git a/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_master_delay.yml b/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_master_delay.yml
index 94a10b2..10f43af 100644
--- a/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_master_delay.yml
+++ b/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_master_delay.yml
@@ -5,7 +5,7 @@
     mysql_params: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
 
   block:
 
diff --git a/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_resetmaster_mode.yml b/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_resetmaster_mode.yml
index 223e325..84a833d 100644
--- a/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_resetmaster_mode.yml
+++ b/tests/integration/targets/test_mysql_replication/tasks/mysql_replication_resetmaster_mode.yml
@@ -5,7 +5,7 @@
     mysql_params: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
 
   block:
 
diff --git a/tests/integration/targets/test_mysql_user/defaults/main.yml b/tests/integration/targets/test_mysql_user/defaults/main.yml
index 5cf9074..a87914c 100644
--- a/tests/integration/targets/test_mysql_user/defaults/main.yml
+++ b/tests/integration/targets/test_mysql_user/defaults/main.yml
@@ -2,7 +2,7 @@
 # defaults file for test_mysql_user
 mysql_user: root
 mysql_password: msandbox
-mysql_host: 127.0.0.1
+mysql_host: '{{ gateway_addr }}'
 mysql_primary_port: 3307
 
 db_name: 'data'
diff --git a/tests/integration/targets/test_mysql_user/meta/main.yml b/tests/integration/targets/test_mysql_user/meta/main.yml
index a7ace5d..4be5f58 100644
--- a/tests/integration/targets/test_mysql_user/meta/main.yml
+++ b/tests/integration/targets/test_mysql_user/meta/main.yml
@@ -1,3 +1,4 @@
+---
 dependencies:
-  - setup_mysql
+  - setup_controller
   - setup_remote_tmp_dir
diff --git a/tests/integration/targets/test_mysql_user/tasks/assert_no_user.yml b/tests/integration/targets/test_mysql_user/tasks/assert_no_user.yml
deleted file mode 100644
index 9861084..0000000
--- a/tests/integration/targets/test_mysql_user/tasks/assert_no_user.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-# test code to assert no mysql user
-# (c) 2014,  Wayne Rosario <wrosario@ansible.com>
-
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
-
-# ============================================================
-- name: run command to query for mysql user
-  command: "{{ mysql_command }} -e \"SELECT User FROM mysql.user where user='{{ user_name }}'\""
-  register: result
-
-- name: assert mysql user is not present
-  assert: { that: "'{{ user_name }}' not in result.stdout" }
diff --git a/tests/integration/targets/test_mysql_user/tasks/assert_user.yml b/tests/integration/targets/test_mysql_user/tasks/assert_user.yml
deleted file mode 100644
index d95d9d2..0000000
--- a/tests/integration/targets/test_mysql_user/tasks/assert_user.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-# test code to assert mysql user
-# (c) 2014,  Wayne Rosario <wrosario@ansible.com>
-
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
-
-# ============================================================
-- name: run command to query for mysql user
-  command: "{{ mysql_command }} -e \"SELECT User FROM mysql.user where user='{{ user_name }}'\""
-  register: result
-
-- name: assert mysql user is present
-  assert:
-    that:
-      - "'{{ user_name }}' in result.stdout"
-
-- name: run command to show privileges for user (expect privileges in stdout)
-  command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name }}'@'localhost'\""
-  register: result
-  when: priv is defined
-
-- name: assert user has giving privileges
-  assert:
-    that:
-      - "'GRANT {{priv}} ON *.*' in result.stdout"
-  when: priv is defined
diff --git a/tests/integration/targets/test_mysql_user/tasks/create_user.yml b/tests/integration/targets/test_mysql_user/tasks/create_user.yml
index 9c3459a..e69de29 100644
--- a/tests/integration/targets/test_mysql_user/tasks/create_user.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/create_user.yml
@@ -1,40 +0,0 @@
-# test code to create mysql user
-# (c) 2014,  Wayne Rosario <wrosario@ansible.com>
-
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
-
-- vars:
-    mysql_parameters: &mysql_params
-      login_user: '{{ mysql_user }}'
-      login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
-      login_port: '{{ mysql_primary_port }}'
-
-  block:
-
-    # ============================================================
-    - name: create mysql user {{user_name}}
-      mysql_user:
-        <<: *mysql_params
-        name: '{{ user_name }}'
-        password: '{{ user_password }}'
-        state: present
-      register: result
-
-    - name: assert output message mysql user was created
-      assert:
-        that:
-          - result is changed
diff --git a/tests/integration/targets/test_mysql_user/tasks/issue-121.yml b/tests/integration/targets/test_mysql_user/tasks/issue-121.yml
index 29241d5..4209c0a 100644
--- a/tests/integration/targets/test_mysql_user/tasks/issue-121.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/issue-121.yml
@@ -1,112 +1,85 @@
 ---
+
 - vars:
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
 
-    # ============================================================
-
-    - name: get server certificate
+    - name: Issue-121 | Setup | Get server certificate
       copy:
-        content: "{{ lookup('pipe', \"openssl s_client -starttls mysql -connect localhost:3307 -showcerts 2>/dev/null </dev/null |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'\") }}"
+        content: "{{ lookup('pipe', \"openssl s_client -starttls mysql -connect {{ mysql_host }}:3307 -showcerts 2>/dev/null </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'\") }}"
         dest: /tmp/cert.pem
       delegate_to: localhost
 
-    - name: get server version
-      mysql_info:
-        <<: *mysql_params
-        filter: version
-      register: db_version
-
-    - set_fact:
-        old_user_mgmt: "{{ db_version.version.major <= 5 and db_version.version.minor <= 6 or db_version.version.major == 10 and db_version.version.minor < 2 | bool }}"
-
-    - name: Drop mysql user if exists
+    - name: Issue-121 | Drop mysql user if exists
       mysql_user:
         <<: *mysql_params
         name: '{{ item }}'
+        host_all: true
         state: absent
-      ignore_errors: yes
-      with_items:
+      ignore_errors: true
+      loop:
         - "{{ user_name_1 }}"
         - "{{ user_name_2 }}"
 
-    - name: create user with REQUIRESSL privilege
-      mysql_user:
-        <<: *mysql_params
-        name: "{{ user_name_1 }}"
-        password: "{{ user_password_1 }}"
-        priv: '*.*:SELECT,CREATE USER,REQUIRESSL,GRANT'
+    # Disabled because:
+    #  - It makes no sense (state changed as nothing to do with a failure)
+    #  - It doesn't work on stable-1
+    # - name: Issue-121 | Create user with REQUIRESSL privilege (expect failure)
+    #   mysql_user:
+    #     <<: *mysql_params
+    #     name: "{{ user_name_1 }}"
+    #     password: "{{ user_password_1 }}"
+    #     priv: '*.*:SELECT,CREATE USER,REQUIRESSL,GRANT'
+    #   register: result
+    #   ignore_errors: true
 
-    - name: verify REQUIRESSL is assigned to the user
-      mysql_query:
-        <<: *mysql_params
-        query: "SHOW {{ what }} '{{ user_name_1}}'@'localhost'"
-      register: result
-      vars:
-        what: "{{ 'GRANTS FOR' if old_user_mgmt else 'CREATE USER' }}"
+    # - name: Issue-121 | Assert error granting privileges
+    #   assert:
+    #     that:
+    #       - result is not changed
 
-    - assert:
-        that:
-          - result is succeeded and 'REQUIRE SSL' in (result.query_result | string)
+    # Disabled on stable-1 because:
+    #  - It doesn't work on stable-1, it's always changed
+    # - name: >-
+    #     Issue-121 | Create user with both REQUIRESSL privilege and an incompatible
+    #     tls_requires option
+    #   mysql_user:
+    #     <<: *mysql_params
+    #     name: "{{ user_name_1 }}"
+    #     host: '{{ gateway_addr }}'
+    #     password: "{{ user_password_1 }}"
+    #     priv: '*.*:SELECT,CREATE USER,REQUIRESSL,GRANT'
+    #     tls_requires:
+    #       X509:
 
-    - name: create user with equivalent ssl requirement in tls_requires (expect unchanged)
-      mysql_user:
-        <<: *mysql_params
-        name: "{{ user_name_1 }}"
-        password: "{{ user_password_1 }}"
-        priv: '*.*:SELECT,CREATE USER,GRANT'
-        tls_requires:
-          SSL:
-      register: result
+    # - name: Issue-121 | Create same user again without REQUIRESSL privilege
+    #   mysql_user:
+    #     <<: *mysql_params
+    #     name: "{{ user_name_1 }}"
+    #     password: "{{ user_password_1 }}"
+    #     priv: '*.*:SELECT,CREATE USER,GRANT'
+    #     tls_requires:
+    #       X509:
+    #   register: result
+    #   ignore_errors: true
 
-    - assert:
-        that:
-          - result is not changed
+    # - name: >-
+    #     Issue-121 | Assert error granting privileges with incompatible tls_requires
+    #     option
+    #   assert:
+    #     that:
+    #       - result is not changed
 
-    - name: create the same user again, with REQUIRESSL privilege once more
-      mysql_user:
-        <<: *mysql_params
-        name: "{{ user_name_1 }}"
-        password: "{{ user_password_1 }}"
-        priv: '*.*:SELECT,CREATE USER,REQUIRESSL,GRANT'
-      register: result
-
-    - assert:
-        that:
-          - result is not changed
-
-    - name: create user with both REQUIRESSL privilege and an incompatible tls_requires option
-      mysql_user:
-        <<: *mysql_params
-        name: "{{ user_name_1 }}"
-        password: "{{ user_password_1 }}"
-        priv: '*.*:SELECT,CREATE USER,REQUIRESSL,GRANT'
-        tls_requires:
-          X509:
-
-    - name: create same user again without REQUIRESSL privilege
-      mysql_user:
-        <<: *mysql_params
-        name: "{{ user_name_1 }}"
-        password: "{{ user_password_1 }}"
-        priv: '*.*:SELECT,CREATE USER,GRANT'
-        tls_requires:
-          X509:
-      register: result
-
-    - assert:
-        that: result is not changed
-
-    - name: Drop mysql user
+    - name: Issue-121 | Teardown | Drop mysql user
       mysql_user:
         <<: *mysql_params
         name: '{{ item }}'
-        host: 127.0.0.1
+        host_all: true
         state: absent
       with_items:
         - "{{ user_name_1 }}"
diff --git a/tests/integration/targets/test_mysql_user/tasks/issue-265.yml b/tests/integration/targets/test_mysql_user/tasks/issue-265.yml
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration/targets/test_mysql_user/tasks/issue-28.yml b/tests/integration/targets/test_mysql_user/tasks/issue-28.yml
index 437ce81..51a2091 100644
--- a/tests/integration/targets/test_mysql_user/tasks/issue-28.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/issue-28.yml
@@ -9,81 +9,87 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
   when: tls_enabled
   block:
 
     # ============================================================
-
-    - name: get server certificate
+    - name: Issue-28 | Setup | Get server certificate
       copy:
-        content: "{{ lookup('pipe', \"openssl s_client -starttls mysql -connect localhost:3307 -showcerts 2>/dev/null </dev/null |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'\") }}"
+        content: "{{ lookup('pipe', \"openssl s_client -starttls mysql -connect {{ mysql_host }}:3307 -showcerts 2>/dev/null </dev/null |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'\") }}"
         dest: /tmp/cert.pem
       delegate_to: localhost
 
-    - name: Drop mysql user if exists
+    - name: Issue-28 | Setup | Drop mysql user if exists
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
+        host_all: true
         state: absent
-      ignore_errors: yes
+      ignore_errors: true
 
-    - name: create user with ssl requirement
+    - name: Issue-28 | Create user with ssl requirement
       mysql_user:
         <<: *mysql_params
         name: "{{ user_name_1 }}"
+        host: '{{ gateway_addr }}'
         password: "{{ user_password_1 }}"
         priv: '*.*:ALL,GRANT'
         tls_requires:
           SSL:
 
-    - name: attempt connection with newly created user (expect failure)
+    - name: Issue-28 | Attempt connection with newly created user (expect failure)
       mysql_user:
         name: "{{ user_name_2 }}"
         password: "{{ user_password_2 }}"
-        host: 127.0.0.1
+        host: '{{ gateway_addr }}'
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
       register: result
-      ignore_errors: yes
+      ignore_errors: true
 
-    - assert:
+    - name: Issue-28 | Assert connection failed
+      assert:
         that:
           - result is failed
-      when: connector_name is search('pymysql')
+      when:
+        - connector_name == 'pymysql'
 
-    - assert:
+    - name: Issue-28 | Assert connection succeeded
+      assert:
         that:
           - result is succeeded
-      when: connector_name is not search('pymysql')
+      when:
+        - connector_name != 'pymysql'
 
-    - name: attempt connection with newly created user ignoring hostname
+    - name: Issue-28 | Attempt connection with newly created user ignoring hostname
       mysql_user:
         name: "{{ user_name_2 }}"
         password: "{{ user_password_2 }}"
-        host: 127.0.0.1
+        host: '{{ gateway_addr }}'
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
-        check_hostname: no
+        check_hostname: false
       register: result
-      ignore_errors: yes
+      ignore_errors: true
 
-    - assert:
+    - name: Issue-28 | Assert connection succeeded
+      assert:
         that:
           - result is succeeded or 'pymysql >= 0.7.11 is required' in result.msg
 
-    - name: Drop mysql user
+    - name: Issue-28 | Drop mysql user
       mysql_user:
         <<: *mysql_params
         name: '{{ item }}'
-        host: 127.0.0.1
+        host: '{{ gateway_addr }}'
         state: absent
       with_items:
         - "{{ user_name_1 }}"
diff --git a/tests/integration/targets/test_mysql_user/tasks/issue-29511.yaml b/tests/integration/targets/test_mysql_user/tasks/issue-29511.yaml
index 31e6edf..17eb200 100644
--- a/tests/integration/targets/test_mysql_user/tasks/issue-29511.yaml
+++ b/tests/integration/targets/test_mysql_user/tasks/issue-29511.yaml
@@ -3,12 +3,12 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
 
-    - name: Issue test setup - drop database
+    - name: Issue-29511 | test setup | drop database
       mysql_db:
         <<: *mysql_params
         name: "{{ item }}"
@@ -17,7 +17,7 @@
         - foo
         - bar
 
-    - name: Issue test setup - create database
+    - name: Issue-29511 | test setup | create database
       mysql_db:
         <<: *mysql_params
         name: "{{ item }}"
@@ -26,7 +26,7 @@
         - foo
         - bar
 
-    - name: Copy SQL scripts to remote
+    - name: Issue-29511 | Copy SQL scripts to remote
       copy:
         src: "{{ item }}"
         dest: "{{ remote_tmp_dir }}/{{ item | basename }}"
@@ -34,13 +34,13 @@
         - create-function.sql
         - create-procedure.sql
 
-    - name: Create function for test
+    - name: Issue-29511 | Create function for test
       shell: "{{ mysql_command }} < {{ remote_tmp_dir }}/create-function.sql"
 
-    - name: Create procedure for test
+    - name: Issue-29511 | Create procedure for test
       shell: "{{ mysql_command }} < {{ remote_tmp_dir }}/create-procedure.sql"
 
-    - name: Create user with FUNCTION and PROCEDURE privileges
+    - name: Issue-29511 | Create user with FUNCTION and PROCEDURE privileges
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
@@ -49,13 +49,13 @@
         priv: 'FUNCTION foo.function:EXECUTE/foo.*:SELECT/PROCEDURE bar.procedure:EXECUTE'
       register: result
 
-    - name: Assert Create user with FUNCTION and PROCEDURE privileges
+    - name: Issue-29511 | Assert Create user with FUNCTION and PROCEDURE privileges
       assert:
         that:
           - result is success
           - result is changed
 
-    - name: Create user with FUNCTION and PROCEDURE privileges - Idempotent check
+    - name: Issue-29511 | Create user with FUNCTION and PROCEDURE privileges - Idempotent check
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
@@ -64,19 +64,13 @@
         priv: 'FUNCTION foo.function:EXECUTE/foo.*:SELECT/PROCEDURE bar.procedure:EXECUTE'
       register: result
 
-    - name: Assert Create user with FUNCTION and PROCEDURE privileges
+    - name: Issue-29511 | Assert Create user with FUNCTION and PROCEDURE privileges
       assert:
         that:
           - result is success
           - result is not changed
 
-    - name: Remove user
-      mysql_user:
-        <<: *mysql_params
-        name: '{{ user_name_2 }}'
-        state: absent
-
-    - name: Issue test teardown - cleanup databases
+    - name: Issue-29511 | Test teardown | cleanup databases
       mysql_db:
         <<: *mysql_params
         name: "{{ item }}"
@@ -84,3 +78,5 @@
       loop:
         - foo
         - bar
+
+    - include: utils/remove_user.yml user_name="{{ user_name_2 }}"
diff --git a/tests/integration/targets/test_mysql_user/tasks/issue-64560.yaml b/tests/integration/targets/test_mysql_user/tasks/issue-64560.yaml
index 1c0af68..a7657f8 100644
--- a/tests/integration/targets/test_mysql_user/tasks/issue-64560.yaml
+++ b/tests/integration/targets/test_mysql_user/tasks/issue-64560.yaml
@@ -3,47 +3,50 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
 
-    - name: Set root password
+    - name: Issue-64560 | Set root password
       mysql_user:
         <<: *mysql_params
         name: root
+        host: '%'
         password: '{{ root_password }}'
         check_implicit_admin: yes
       register: result
 
-    - name: assert root password is changed
+    - name: Issue-64560 | Assert root password is changed
       assert:
         that:
           - result is changed
 
-    - name: Set root password again
+    - name: Issue-64560 | Set root password again
       mysql_user:
         login_user: '{{ mysql_user }}'
         login_password: '{{ root_password }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         name: root
+        host: '%'
         password: '{{ root_password }}'
         check_implicit_admin: yes
       register: result
 
-    - name: Assert root password is not changed
+    - name: Issue-64560 | Assert root password is not changed
       assert:
         that:
           - result is not changed
 
-    - name: Set root password again
+    - name: Issue-64560 | Set root password again
       mysql_user:
         login_user: '{{ mysql_user }}'
         login_password: '{{ root_password }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         name: root
+        host: '%'
         password: '{{ mysql_password }}'
         check_implicit_admin: yes
       register: result
diff --git a/tests/integration/targets/test_mysql_user/tasks/main.yml b/tests/integration/targets/test_mysql_user/tasks/main.yml
index 5ddf300..2569d4a 100644
--- a/tests/integration/targets/test_mysql_user/tasks/main.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/main.yml
@@ -1,3 +1,4 @@
+---
 ####################################################################
 # WARNING: These are designed specifically for Ansible tests       #
 # and should not be used as examples of how to write Ansible roles #
@@ -24,15 +25,12 @@
 # ============================================================
 # create mysql user and verify user is added to mysql database
 #
-- name: alias mysql command to include default options
-  set_fact:
-    mysql_command: "mysql -u{{ mysql_user }} -p{{ mysql_password }} -P{{ mysql_primary_port }} --protocol=tcp"
 
 - vars:
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
@@ -41,109 +39,49 @@
 
     - include: issue-28.yml
 
-    - include: create_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }}
+    - include: test_resource_limits.yml
 
-    - include: resource_limits.yml
-
-    - include: assert_user.yml user_name={{user_name_1}}
-
-    - include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }}
-
-    - include: assert_no_user.yml user_name={{user_name_1}}
-
-    # ============================================================
-    # Create mysql user that already exist on mysql database
-    #
-    - include: create_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }}
-
-    - name: create mysql user that already exist (expect changed=false)
-      mysql_user:
-        <<: *mysql_params
-        name: '{{user_name_1}}'
-        password: '{{user_password_1}}'
-        state: present
-      register: result
-
-    - name: assert output message mysql user was not created
-      assert:
-        that:
-          - result is not changed
-
-    # ============================================================
-    # remove mysql user and verify user is removed from mysql database
-    #
-    - name: remove mysql user state=absent (expect changed=true)
-      mysql_user:
-        <<: *mysql_params
-        name: '{{ user_name_1 }}'
-        password: '{{ user_password_1 }}'
-        state: absent
-      register: result
-
-    - name: assert output message mysql user was removed
-      assert:
-        that:
-          - result is changed
-
-    - include: assert_no_user.yml user_name={{user_name_1}}
-
-    # ============================================================
-    # remove mysql user that does not exist on mysql database
-    #
-    - name: remove mysql user that does not exist state=absent (expect changed=false)
-      mysql_user:
-        <<: *mysql_params
-        name: '{{ user_name_1 }}'
-        password: '{{ user_password_1 }}'
-        state: absent
-      register: result
-
-    - name: assert output message mysql user that does not exist
-      assert:
-        that:
-          - result is not changed
-
-    - include: assert_no_user.yml user_name={{user_name_1}}
+    - include: test_idempotency.yml
 
     # ============================================================
     # Create user with no privileges and verify default privileges are assign
     #
-    - name: create user with select privilege state=present (expect changed=true)
+    - name: create user with DEFAULT privilege state=present (expect changed=true)
       mysql_user:
         <<: *mysql_params
-        name: '{{ user_name_1 }}'
-        password: '{{ user_password_1 }}'
+        name: "{{ user_name_1 }}"
+        password: "{{ user_password_1 }}"
         state: present
       register: result
 
-    - include: assert_user.yml user_name={{user_name_1}} priv=USAGE
+    - include: utils/assert_user.yml user_name={{ user_name_1 }} user_host=localhost priv=USAGE
 
-    - include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }}
+    - include: utils/remove_user.yml user_name={{ user_name_1 }}
 
-    - include: assert_no_user.yml user_name={{user_name_1}}
+    - include: utils/assert_no_user.yml user_name={{ user_name_1 }}
 
     # ============================================================
     # Create user with select privileges and verify select privileges are assign
     #
-    - name: create user with select privilege state=present (expect changed=true)
+    - name: Create user with SELECT privilege state=present (expect changed=true)
       mysql_user:
         <<: *mysql_params
-        name: '{{ user_name_2 }}'
-        password: '{{ user_password_2 }}'
+        name: "{{ user_name_2 }}"
+        password: "{{ user_password_2 }}"
         state: present
         priv: '*.*:SELECT'
       register: result
 
-    - include: assert_user.yml user_name={{user_name_2}} priv=SELECT
+    - include: utils/assert_user.yml user_name={{ user_name_2 }} user_host=localhost priv=SELECT
 
-    - include: remove_user.yml user_name={{user_name_2}} user_password={{ user_password_2 }}
+    - include: utils/remove_user.yml user_name={{ user_name_2 }}
 
-    - include: assert_no_user.yml user_name={{user_name_2}}
+    - include: utils/assert_no_user.yml user_name={{ user_name_2 }}
 
     # ============================================================
     # Assert user has access to multiple databases
     #
-    - name: give users access to multiple databases
+    - name: Give users access to multiple databases
       mysql_user:
         <<: *mysql_params
         name: '{{ item[0] }}'
@@ -151,34 +89,34 @@
         append_privs: yes
         password: '{{ user_password_1 }}'
       with_nested:
-        - [ '{{ user_name_1 }}', '{{ user_name_2 }}']
+        - ['{{ user_name_1 }}', '{{ user_name_2 }}']
         - "{{db_names}}"
 
-    - name: show grants access for user1 on multiple database
+    - name: Show grants access for user1 on multiple database
       command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_1 }}'@'localhost'\""
       register: result
 
-    - name: assert grant access for user1 on multiple database
+    - name: Assert grant access for user1 on multiple database
       assert:
         that:
           - "'{{ item }}' in result.stdout"
-      with_items: "{{db_names}}"
+      with_items: "{{ db_names }}"
 
-    - name: show grants access for user2 on multiple database
+    - name: Show grants access for user2 on multiple database
       command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_2 }}'@'localhost'\""
       register: result
 
-    - name: assert grant access for user2 on multiple database
+    - name: Assert grant access for user2 on multiple database
       assert:
         that:
           - "'{{ item }}' in result.stdout"
       with_items: "{{db_names}}"
 
-    - include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }}
+    - include: utils/remove_user.yml user_name={{ user_name_1 }}
 
-    - include: remove_user.yml user_name={{user_name_2}} user_password={{ user_password_1 }}
+    - include: utils/remove_user.yml user_name={{ user_name_2 }}
 
-    - name: give user access to database via wildcard
+    - name: Give user SELECT access to database via wildcard
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
@@ -186,7 +124,7 @@
         append_privs: yes
         password: '{{ user_password_1 }}'
 
-    - name: show grants access for user1 on multiple database
+    - name: Show grants access for user1 on database via wildcard
       command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_1 }}'@'localhost'\""
       register: result
 
@@ -201,8 +139,8 @@
         <<: *mysql_params
         name: '{{ user_name_1 }}'
         priv:
-        - unsuitable
-        - type
+          - unsuitable
+          - type
         append_privs: yes
         host_all: yes
         password: '{{ user_password_1 }}'
@@ -215,7 +153,7 @@
           - result is failed
           - result.msg is search('priv parameter must be str or dict')
 
-    - name: change user access to database via wildcard
+    - name: Change SELECT to INSERT for user access to database via wildcard
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
@@ -224,7 +162,7 @@
         host_all: yes
         password: '{{ user_password_1 }}'
 
-    - name: show grants access for user1 on multiple database
+    - name: Show grants access for user1 on database via wildcard
       command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_1 }}'@'localhost'\""
       register: result
 
@@ -234,7 +172,7 @@
           - "'%db' in result.stdout"
           - "'INSERT' in result.stdout"
 
-    - include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }}
+    - include: utils/remove_user.yml user_name={{user_name_1}}
 
     # ============================================================
     # Test plaintext and encrypted password scenarios.
@@ -246,7 +184,7 @@
     #
     # FIXME: mariadb sql syntax for create/update user is not compatible
     - include: test_user_plugin_auth.yml
-      when: install_type == 'mysql'
+      when: db_engine == 'mysql'
 
     # ============================================================
     # Assert create user with SELECT privileges, attempt to create database and update privileges to create database
@@ -277,7 +215,7 @@
     - include: test_priv_append.yml enable_check_mode=yes
 
     # Tests for the TLS requires dictionary
-    - include: tls_requirements.yml
+    - include: test_tls_requirements.yml
 
     - import_tasks: issue-29511.yaml
       tags:
@@ -289,3 +227,5 @@
 
     # https://github.com/ansible-collections/community.mysql/issues/231
     - include: test_user_grants_with_roles_applied.yml
+
+    - include: test_revoke_only_grant.yml
diff --git a/tests/integration/targets/test_mysql_user/tasks/remove_user.yml b/tests/integration/targets/test_mysql_user/tasks/remove_user.yml
deleted file mode 100644
index 7a2c9e9..0000000
--- a/tests/integration/targets/test_mysql_user/tasks/remove_user.yml
+++ /dev/null
@@ -1,74 +0,0 @@
-# test code to remove mysql user
-# (c) 2014,  Wayne Rosario <wrosario@ansible.com>
-
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
-
-- vars:
-    mysql_parameters: &mysql_params
-      login_user: '{{ mysql_user }}'
-      login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
-      login_port: '{{ mysql_primary_port }}'
-
-  block:
-
-    # ============================================================
-    - name: remove mysql user {{user_name}}
-      mysql_user:
-        <<: *mysql_params
-        name: '{{user_name}}'
-        password: '{{user_password}}'
-        state: absent
-      register: result
-
-    - name: assert output message mysql user was removed
-      assert:
-        that:
-          - result is changed
-
-    # ============================================================
-    - name: create blank mysql user to be removed later
-      mysql_user:
-        <<: *mysql_params
-        name: ""
-        state: present
-        password: 'KJFDY&D*Sfuydsgf'
-
-    - name: remove blank mysql user with hosts=all (expect changed)
-      mysql_user:
-        <<: *mysql_params
-        user: ""
-        host_all: true
-        state: absent
-      register: result
-
-    - name: assert changed is true for removing all blank users
-      assert:
-        that:
-          - result is changed
-
-    - name: remove blank mysql user with hosts=all (expect ok)
-      mysql_user:
-        <<: *mysql_params
-        user: ""
-        host_all: true
-        state: absent
-      register: result
-
-    - name: assert changed is true for removing all blank users
-      assert:
-        that:
-          - result is not changed
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_idempotency.yml b/tests/integration/targets/test_mysql_user/tasks/test_idempotency.yml
new file mode 100644
index 0000000..cc6850c
--- /dev/null
+++ b/tests/integration/targets/test_mysql_user/tasks/test_idempotency.yml
@@ -0,0 +1,84 @@
+---
+- vars:
+    mysql_parameters: &mysql_params
+      login_user: '{{ mysql_user }}'
+      login_password: '{{ mysql_password }}'
+      login_host: '{{ mysql_host }}'
+      login_port: '{{ mysql_primary_port }}'
+
+  block:
+    # ========================================================================
+    # Creation
+    # ========================================================================
+    - include: utils/create_user.yml user_name={{ user_name_1 }} user_password={{ user_password_1 }}
+
+    - name: Idempotency | Create user that already exist (expect changed=false)
+      mysql_user:
+        <<: *mysql_params
+        name: "{{ user_name_1 }}"
+        password: "{{ user_password_1 }}"
+        state: present
+      register: result
+
+    - name: Idempotency | Assert create user task is not changed
+      assert: {that: [result is not changed]}
+
+    # ========================================================================
+    # Removal
+    # ========================================================================
+    - name: Idempotency | Remove user (expect changed=true)
+      mysql_user:
+        <<: *mysql_params
+        name: "{{ user_name_1 }}"
+        state: absent
+      register: result
+
+    - name: Idempotency | Assert remove user task is changed
+      ansible.builtin.assert:
+        that:
+          - result is changed
+
+    - name: Idempotency | Remove user that doesn't exists (expect changed=false)
+      mysql_user:
+        <<: *mysql_params
+        name: "{{ user_name_1 }}"
+        state: absent
+      register: result
+
+    - name: Idempotency | Assert remove user task is not changed
+      ansible.builtin.assert:
+        that:
+          - result is not changed
+
+    # ========================================================================
+    # Removal with host_all
+    # ========================================================================
+
+    # Create blank  user to be removed later
+    - include: utils/create_user.yml user_name="" user_password='KJFDY&D*Sfuysf'
+
+    - name: Idempotency | Remove blank  user with hosts=all (expect changed)
+      mysql_user:
+        <<: *mysql_params
+        user: ""
+        host_all: true
+        state: absent
+      register: result
+
+    - name: Idempotency | Assert removing all blank users is changed
+      ansible.builtin.assert:
+        that:
+          - result is changed
+
+    - name: Idempotency | Remove blank user with hosts=all (expect ok)
+      mysql_user:
+        <<: *mysql_params
+        user: ""
+        host_all: true
+        state: absent
+      register: result
+
+    - name: Idempotency | Assert removing all blank users is not changed
+      ansible.builtin.assert:
+        that:
+          - result is not changed
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_priv_append.yml b/tests/integration/targets/test_mysql_user/tasks/test_priv_append.yml
index 72e933b..3fa317f 100644
--- a/tests/integration/targets/test_mysql_user/tasks/test_priv_append.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/test_priv_append.yml
@@ -1,45 +1,48 @@
+---
 # Test code to ensure that appending privileges will not result in unnecessary changes when the current privileges
 # are a superset of the new privileges that have been defined.
 - vars:
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
 
-    - name: Create test databases
+    - name: Priv append | Create test databases
       mysql_db:
         <<: *mysql_params
         name: '{{ item }}'
         state: present
       loop:
-      - data1
-      - data2
+        - data1
+        - data2
 
-    - name: Create a user with an initial set of privileges
+    - name: Priv append | Create a user with an initial set of privileges
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_4 }}'
+        host: '%'
         password: '{{ user_password_4 }}'
         priv: 'data1.*:SELECT,INSERT/data2.*:SELECT,DELETE'
         state: present
 
-    - name: Run command to show privileges for user (expect privileges in stdout)
-      command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_4 }}'@'localhost'\""
+    - name: Priv append | Run command to show privileges for user (expect privileges in stdout)
+      command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_4 }}'@'%'\""
       register: result
 
-    - name: Assert that the initial set of privileges matches what is expected
+    - name: Priv append | Assert that the initial set of privileges matches what is expected
       assert:
         that:
           - "'GRANT SELECT, INSERT ON `data1`.*' in result.stdout"
           - "'GRANT SELECT, DELETE ON `data2`.*' in result.stdout"
 
-    - name: Append privileges that are a subset of the current privileges, which should be a no-op
+    - name: Priv append | Append privileges that are a subset of the current privileges, which should be a no-op
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_4 }}'
+        host: '%'
         password: '{{ user_password_4 }}'
         priv: 'data1.*:SELECT/data2.*:SELECT'
         append_privs: yes
@@ -47,25 +50,26 @@
       check_mode: '{{ enable_check_mode }}'
       register: result
 
-    - name: Assert that there wasn't a change in permissions
+    - name: Priv append | Assert that there wasn't a change in permissions
       assert:
         that:
           - result is not changed
 
-    - name: Run command to show privileges for user (expect privileges in stdout)
-      command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_4 }}'@'localhost'\""
+    - name: Priv append | Run command to show privileges for user (expect privileges in stdout)
+      command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_4 }}'@'%'\""
       register: result
 
-    - name: Assert that the permissions still match what was originally granted
+    - name: Priv append | Assert that the permissions still match what was originally granted
       assert:
         that:
           - "'GRANT SELECT, INSERT ON `data1`.*' in result.stdout"
           - "'GRANT SELECT, DELETE ON `data2`.*' in result.stdout"
 
-    - name: Append privileges that are not included in the current set of privileges to test that privileges are updated
+    - name: Priv append | Append privileges that are not included in the current set of privileges to test that privileges are updated
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_4 }}'
+        host: '%'
         password: '{{ user_password_4 }}'
         priv: 'data1.*:DELETE/data2.*:SELECT'
         append_privs: yes
@@ -73,29 +77,51 @@
       check_mode: '{{ enable_check_mode }}'
       register: result
 
-    - name: Assert that there was a change because permissions were added to data1.*
+    - name: Priv append | Assert that there was a change because permissions were added to data1.*
       assert:
         that:
           - result is changed
 
-    - name: Run command to show privileges for user (expect privileges in stdout)
-      command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_4 }}'@'localhost'\""
+    - name: Priv append | Run command to show privileges for user (expect privileges in stdout)
+      command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_4 }}'@'%'\""
       register: result
 
-    - name: Assert that the permissions were changed as expected if check_mode is set to 'no'
+    - name: Priv append | Assert that the permissions were changed as expected if check_mode is set to 'no'
       assert:
         that:
           - "'GRANT SELECT, INSERT, DELETE ON `data1`.*' in result.stdout"
           - "'GRANT SELECT, DELETE ON `data2`.*' in result.stdout"
       when: enable_check_mode == 'no'
 
-    - name: Assert that the permissions were not actually changed if check_mode is set to 'yes'
+    - name: Priv append | Assert that the permissions were not actually changed if check_mode is set to 'yes'
       assert:
         that:
           - "'GRANT SELECT, INSERT ON `data1`.*' in result.stdout"
           - "'GRANT SELECT, DELETE ON `data2`.*' in result.stdout"
       when: enable_check_mode == 'yes'
 
+    - name: Priv append | Try to append invalid privileges
+      mysql_user:
+        <<: *mysql_params
+        name: '{{ user_name_4 }}'
+        host: '%'
+        password: '{{ user_password_4 }}'
+        priv: 'data1.*:INVALID/data2.*:SELECT'
+        append_privs: yes
+        state: present
+      check_mode: '{{ enable_check_mode }}'
+      register: result
+      ignore_errors: true
+
+    - name: Priv append | Assert that there wasn't a change in privileges if check_mode is set to 'no'
+      assert:
+        that:
+          - result is failed
+          - >
+            'Error granting privileges' in result.msg
+            or 'invalid privileges string' in result.msg
+      when: enable_check_mode == 'no'
+
     ##########
     # Clean up
     - name: Drop test databases
@@ -104,11 +130,7 @@
         name: '{{ item }}'
         state: present
       loop:
-      - data1
-      - data2
+        - data1
+        - data2
 
-    - name: Drop test user
-      mysql_user:
-        <<: *mysql_params
-        name: '{{ user_name_4 }}'
-        state: absent
+    - include: utils/remove_user.yml user_name={{ user_name_4 }}
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_priv_dict.yml b/tests/integration/targets/test_mysql_user/tasks/test_priv_dict.yml
index d54c946..82385e1 100644
--- a/tests/integration/targets/test_mysql_user/tasks/test_priv_dict.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/test_priv_dict.yml
@@ -1,24 +1,25 @@
+---
 - vars:
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
 
     # Tests for priv parameter value passed as a dict
-    - name: Create test databases
+    - name: Priv dict | Create test databases
       mysql_db:
         <<: *mysql_params
         name: '{{ item }}'
         state: present
       loop:
-      - data1
-      - data2
-      - data3
+        - data1
+        - data2
+        - data3
 
-    - name: Create user with privileges
+    - name: Priv dict | Create user with privileges
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_3 }}'
@@ -28,7 +29,7 @@
           "data2.*": "SELECT"
         state: present
 
-    - name: Run command to show privileges for user (expect privileges in stdout)
+    - name: Priv dict | Run command to show privileges for user (expect privileges in stdout)
       command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_3 }}'@'localhost'\""
       register: result
 
@@ -39,12 +40,12 @@
           - "'GRANT SELECT ON `data2`.*' in result.stdout"
 
     # Issue https://github.com/ansible-collections/community.mysql/issues/99
-    - name: Create test table test_table_issue99
+    - name: Priv dict | Create test table test_table_issue99
       mysql_query:
         <<: *mysql_params
         query: "CREATE TABLE IF NOT EXISTS data3.test_table_issue99 (a INT, b INT, c INT)"
 
-    - name: Grant select on a column
+    - name: Priv dict | Grant select on a column
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_3 }}'
@@ -52,11 +53,12 @@
           'data3.test_table_issue99': 'SELECT (a)'
       register: result
 
-    - assert:
+    - name: Priv dict | Assert that select on a column is changed
+      assert:
         that:
-        - result is changed
+          - result is changed
 
-    - name: Grant select on the column again
+    - name: Priv dict | Grant select on the column again
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_3 }}'
@@ -64,12 +66,12 @@
           'data3.test_table_issue99': 'SELECT (a)'
       register: result
 
-    - assert:
+    - name: Priv dict | Assert that select on the column is not changed
+      assert:
         that:
-        - result is not changed
+          - result is not changed
 
-
-    - name: Grant select on columns
+    - name: Priv dict | Grant select on columns
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_3 }}'
@@ -77,11 +79,12 @@
           'data3.test_table_issue99': 'SELECT (a, b),INSERT'
       register: result
 
-    - assert:
+    - name: Priv dict | Assert select on columns is changed
+      assert:
         that:
-        - result is changed
+          - result is changed
 
-    - name: Grant select on columns again
+    - name: Priv dict | Grant select on columns again
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_3 }}'
@@ -89,11 +92,12 @@
           'data3.test_table_issue99': 'SELECT (a, b),INSERT'
       register: result
 
-    - assert:
+    - name: Priv dict | Assert that select on columns again is not changed
+      assert:
         that:
-        - result is not changed
+          - result is not changed
 
-    - name: Grant privs on columns
+    - name: Priv dict | Grant privs on columns
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_3 }}'
@@ -101,11 +105,12 @@
           'data3.test_table_issue99': 'SELECT (a, b), INSERT (a, b), UPDATE'
       register: result
 
-    - assert:
+    - name: Priv dict | Assert that grant privs on columns is changed
+      assert:
         that:
-        - result is changed
+          - result is changed
 
-    - name: Grant same privs on columns again, note that the column order is different
+    - name: Priv dict | Grant same privs on columns again, note that the column order is different
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_3 }}'
@@ -113,21 +118,22 @@
           'data3.test_table_issue99': 'SELECT (a, b), UPDATE, INSERT (b, a)'
       register: result
 
-    - assert:
+    - name: Priv dict | Assert that grants same privs with different order is not changed
+      assert:
         that:
-        - result is not changed
+          - result is not changed
 
-    - name: Run command to show privileges for user (expect privileges in stdout)
+    - name: Priv dict | Run command to show privileges for user (expect privileges in stdout)
       command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_3 }}'@'localhost'\""
       register: result
 
-    - name: Assert user has giving privileges
+    - name: Priv dict | Assert user has giving privileges
       assert:
         that:
           - "'GRANT SELECT (`A`, `B`), INSERT (`A`, `B`), UPDATE' in result.stdout"
       when: "'(`A`, `B`)' in result.stdout"
 
-    - name: Assert user has giving privileges
+    - name: Priv dict | Assert user has giving privileges
       assert:
         that:
           - "'GRANT SELECT (A, B), INSERT (A, B), UPDATE' in result.stdout"
@@ -135,18 +141,14 @@
 
     ##########
     # Clean up
-    - name: Drop test databases
+    - name: Priv dict | Drop test databases
       mysql_db:
         <<: *mysql_params
         name: '{{ item }}'
         state: present
       loop:
-      - data1
-      - data2
-      - data3
+        - data1
+        - data2
+        - data3
 
-    - name: Drop test user
-      mysql_user:
-        <<: *mysql_params
-        name: '{{ user_name_3 }}'
-        state: absent
+    - include: utils/remove_user.yml user_name="{{ user_name_3 }}"
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_priv_subtract.yml b/tests/integration/targets/test_mysql_user/tasks/test_priv_subtract.yml
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_privs.yml b/tests/integration/targets/test_mysql_user/tasks/test_privs.yml
index 17e42b3..55ac62d 100644
--- a/tests/integration/targets/test_mysql_user/tasks/test_privs.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/test_privs.yml
@@ -1,3 +1,4 @@
+---
 # test code for privileges for mysql_user module
 # (c) 2014,  Wayne Rosario <wrosario@ansible.com>
 
@@ -20,56 +21,58 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
 
     # ============================================================
-    - name: create user with basic select privileges
+    - name: Privs | Create user with basic select privileges
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
+        host: '%'
         password: '{{ user_password_2 }}'
         priv: '*.*:SELECT'
         state: present
       when: current_append_privs ==  "yes"
 
-    - include: assert_user.yml user_name={{user_name_2}} priv='SELECT'
+    - include: utils/assert_user.yml user_name={{ user_name_2 }} user_host=% priv='SELECT'
       when: current_append_privs ==  "yes"
 
-    - name: create user with current privileges (expect changed=true)
+    - name: Privs | Create user with current privileges (expect changed=true)
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
+        host: '%'
         password: '{{ user_password_2 }}'
-        priv: '*.*:{{current_privilege}}'
-        append_privs: '{{current_append_privs}}'
+        priv: '*.*:{{ current_privilege }}'
+        append_privs: '{{ current_append_privs }}'
         state: present
       register: result
 
-    - name: assert output message for current privileges
+    - name: Privs | Assert output message for current privileges
       assert:
         that:
           - result is changed
 
-    - name: run command to show privileges for user (expect privileges in stdout)
-      command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{user_name_2}}'@'localhost'\""
+    - name: Privs | Run command to show privileges for user (expect privileges in stdout)
+      command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{user_name_2}}'@'%'\""
       register: result
 
-    - name: assert user has correct privileges
+    - name: Privs | Assert user has correct privileges
       assert:
         that:
-          - "'GRANT {{current_privilege | replace(',', ', ')}} ON *.*' in result.stdout"
+          - "'GRANT {{ current_privilege | replace(',', ', ') }} ON *.*' in result.stdout"
       when: current_append_privs ==  "no"
 
-    - name: assert user has correct privileges
+    - name: Privs | Assert user has correct privileges
       assert:
         that:
-          - "'GRANT SELECT, {{current_privilege | replace(',', ', ')}} ON *.*' in result.stdout"
+          - "'GRANT SELECT, {{ current_privilege | replace(',', ', ') }} ON *.*' in result.stdout"
       when: current_append_privs ==  "yes"
 
-    - name: create database using user current privileges
+    - name: Privs | Create database using user current privileges
       mysql_db:
         login_user: '{{ user_name_2 }}'
         login_password: '{{ user_password_2 }}'
@@ -79,56 +82,59 @@
         state: present
       ignore_errors: true
 
-    - name: run command to test that database was not created
+    - name: Privs | Run command to test that database was not created
       command: "{{ mysql_command }} -e \"show databases like '{{ db_name }}'\""
       register: result
 
-    - name: assert database was not created
+    - name: Privs | Assert database was not created
       assert:
         that:
-          - "'{{ db_name }}' not in result.stdout"
+          - db_name not in result.stdout
 
     # ============================================================
-    - name: Add privs to a specific table (expect changed)
+    - name: Privs | Add privs to a specific table (expect changed)
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
+        host: '%'
         password: '{{ user_password_2 }}'
         priv: 'jmainguy.jmainguy:ALL'
         state: present
       register: result
 
-    - name: Assert that priv changed
+    - name: Privs | Assert that priv changed
       assert:
         that:
           - result is changed
 
-    - name: Add privs to a specific table (expect ok)
+    - name: Privs | Add privs to a specific table (expect ok)
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
+        host: '%'
         password: '{{ user_password_2 }}'
         priv: 'jmainguy.jmainguy:ALL'
         state: present
       register: result
 
-    - name: Assert that priv did not change
+    - name: Privs | Assert that priv did not change
       assert:
         that:
           - result is not changed
 
     # ============================================================
-    - name: update user with all privileges
+    - name: Privs | Grant ALL to user {{ user_name_2 }}
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
+        host: '%'
         password: '{{ user_password_2 }}'
         priv: '*.*:ALL'
         state: present
 
-    # - include: assert_user.yml user_name={{user_name_2}} priv='ALL PRIVILEGES'
+    # - include: utils/assert_user.yml user_name={{user_name_2}} user_host=% priv='ALL PRIVILEGES'
 
-    - name: create database using user
+    - name: Privs | Create database using user {{ user_name_2 }}
       mysql_db:
         login_user: '{{ user_name_2 }}'
         login_password: '{{ user_password_2 }}'
@@ -137,10 +143,10 @@
         name: '{{ db_name }}'
         state: present
 
-    - name: run command to test database was created using user new privileges
+    - name: Privs | Run command to test database was created using user new privileges
       command: "{{ mysql_command }} -e \"SHOW CREATE DATABASE {{ db_name }}\""
 
-    - name: drop database using user
+    - name: Privs | Drop database using user {{ user_name_2 }}
       mysql_db:
         login_user: '{{ user_name_2 }}'
         login_password: '{{ user_password_2 }}'
@@ -150,37 +156,95 @@
         state: absent
 
     # ============================================================
-    - name: update user with a long privileges list (mysql has a special multiline grant output)
+    - name: Privs | Update user with a long privileges list (mysql has a special multiline grant output)
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
+        host: '%'
         password: '{{ user_password_2 }}'
         priv: '*.*:CREATE USER,FILE,PROCESS,RELOAD,REPLICATION CLIENT,REPLICATION SLAVE,SHOW DATABASES,SHUTDOWN,SUPER,CREATE,DROP,EVENT,LOCK TABLES,INSERT,UPDATE,DELETE,SELECT,SHOW VIEW,GRANT'
         state: present
       register: result
 
-    - name: Assert that priv changed
+    - name: Privs | Assert that priv changed
       assert:
         that:
           - result is changed
 
-    - name: Test idempotency (expect ok)
+    - name: Privs | Test idempotency with a long privileges list (expect ok)
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
+        host: '%'
         password: '{{ user_password_2 }}'
         priv: '*.*:CREATE USER,FILE,PROCESS,RELOAD,REPLICATION CLIENT,REPLICATION SLAVE,SHOW DATABASES,SHUTDOWN,SUPER,CREATE,DROP,EVENT,LOCK TABLES,INSERT,UPDATE,DELETE,SELECT,SHOW VIEW,GRANT'
         state: present
       register: result
 
-    - name: Assert that priv did not change
+    # FIXME: on mysql >=8 and mariadb >=10.5.2 there's always a change because
+    # the REPLICATION CLIENT privilege was renamed to BINLOG MONITOR
+    - name: Privs | Assert that priv did not change
       assert:
         that:
           - result is not changed
-      when: install_type == 'mysql' or (install_type == 'mariadb' and mariadb_version is version('10.2', '=='))
+
+    - include: utils/remove_user.yml user_name="{{ user_name_2 }}"
 
     # ============================================================
-    - name: update user with invalid privileges
+    - name: Privs | Grant all privileges with grant option
+      mysql_user:
+        <<: *mysql_params
+        name: '{{ user_name_2 }}'
+        password: '{{ user_password_2 }}'
+        priv: '*.*:ALL,GRANT'
+        state: present
+      register: result
+
+    - name: Privs | Assert that priv changed
+      assert:
+        that:
+          - result is changed
+
+    - name: Privs | Collect user info by host
+      community.mysql.mysql_info:
+        <<: *mysql_params
+        filter: "users"
+      register: mysql_info_about_users
+
+    - name: Privs | Assert that 'GRANT' permission is present
+      assert:
+        that:
+          - mysql_info_about_users.users.localhost.{{ user_name_2 }}.Grant_priv == 'Y'
+
+    # Disabled on stable-1 because always returns changed.
+    # - name: Privs | Test idempotency (expect ok)
+    #   mysql_user:
+    #     <<: *mysql_params
+    #     name: '{{ user_name_2 }}'
+    #     password: '{{ user_password_2 }}'
+    #     priv: '*.*:CREATE USER,FILE,PROCESS,RELOAD,REPLICATION CLIENT,REPLICATION SLAVE,SHOW DATABASES,SHUTDOWN,SUPER,CREATE,DROP,EVENT,LOCK TABLES,INSERT,UPDATE,DELETE,SELECT,SHOW VIEW,GRANT'
+    #     state: present
+    #   register: result
+
+    # # FIXME: on mysql >=8 there's always a change (ALL PRIVILEGES -> specific privileges)
+    # - name: Privs | Assert that priv did not change
+    #   assert:
+    #     that:
+    #       - result is not changed
+
+    - name: Privs | Collect user info by host
+      community.mysql.mysql_info:
+        <<: *mysql_params
+        filter: "users"
+      register: mysql_info_about_users
+
+    - name: Privs | Assert that 'GRANT' permission is present (by host)
+      assert:
+        that:
+          - mysql_info_about_users.users.localhost.{{ user_name_2 }}.Grant_priv == 'Y'
+
+    # ============================================================
+    - name: Privs | Update user with invalid privileges
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_2 }}'
@@ -190,14 +254,9 @@
       register: result
       ignore_errors: yes
 
-    - name: Assert that priv did not change
+    - name: Privs | Assert that priv did not change
       assert:
         that:
           - result is failed
 
-    - name: remove username
-      mysql_user:
-        <<: *mysql_params
-        name: '{{ user_name_2 }}'
-        password: '{{ user_password_2 }}'
-        state: absent
+    - include: utils/remove_user.yml user_name="{{ user_name_2 }}"
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_privs_issue_465.yml b/tests/integration/targets/test_mysql_user/tasks/test_privs_issue_465.yml
new file mode 100644
index 0000000..2e6a41e
--- /dev/null
+++ b/tests/integration/targets/test_mysql_user/tasks/test_privs_issue_465.yml
@@ -0,0 +1,31 @@
+---
+# test code for privileges for mysql_user module - issue 465
+
+- vars:
+    mysql_parameters: &mysql_params
+      login_user: '{{ mysql_user }}'
+      login_password: '{{ mysql_password }}'
+      login_host: '{{ mysql_host }}'
+      login_port: '{{ mysql_primary_port }}'
+
+  block:
+
+    # ============================================================
+    - name: Privs issue 465 | Create a user with parameters that will always cause an exception
+      mysql_user:
+        <<: *mysql_params
+        name: user_issue_465
+        password: a_test_password_465
+        priv: '*.{{ db_name }}:SELECT'
+        state: present
+      ignore_errors: true
+      register: result
+
+    - name: Privs issue 465 | Assert output message for current privileges
+      assert:
+        that:
+          - result is failed
+          - result.msg is search('invalid priv string')
+          - result.msg is search('params')
+          - result.msg is search('query')
+          - result.msg is search('exception')
diff --git a/tests/integration/targets/test_mysql_user/tasks/resource_limits.yml b/tests/integration/targets/test_mysql_user/tasks/test_resource_limits.yml
similarity index 60%
rename from tests/integration/targets/test_mysql_user/tasks/resource_limits.yml
rename to tests/integration/targets/test_mysql_user/tasks/test_resource_limits.yml
index 736adb3..7c2b97b 100644
--- a/tests/integration/targets/test_mysql_user/tasks/resource_limits.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/test_resource_limits.yml
@@ -1,20 +1,22 @@
+---
 # test code for resource_limits parameter
 - vars:
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
 
-    - name: Drop mysql user {{ user_name_1 }} if exists
+    - name: Resource limits | Drop mysql user {{ user_name_1 }} if exists
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
+        host_all: true
         state: absent
 
-    - name: Create mysql user {{ user_name_1 }} with resource limits in check_mode
+    - name: Resource limits | Create mysql user {{ user_name_1 }} with resource limits in check_mode
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
@@ -26,11 +28,12 @@
       check_mode: yes
       register: result
 
-    - assert:
+    - name: Resource limits | Assert that create user with resource limits is changed
+      assert:
         that:
           - result is changed
 
-    - name: Create mysql user {{ user_name_1 }} with resource limits in actual mode
+    - name: Resource limits | Create mysql user {{ user_name_1 }} with resource limits in actual mode
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
@@ -45,19 +48,23 @@
         that:
           - result is changed
 
-    - name: Check
+    - name: Resource limits | Retrieve user
       mysql_query:
         <<: *mysql_params
         query: >
-          SELECT User FROM mysql.user WHERE User = '{{ user_name_1 }}' AND Host = 'localhost'
-          AND max_questions = 10 AND max_connections = 5
+          SELECT User FROM mysql.user
+          WHERE User = '{{ user_name_1 }}'
+          AND Host = 'localhost'
+          AND max_questions = 10
+          AND max_connections = 5
       register: result
 
-    - assert:
+    - name: Resource limits | Assert that rowcount is 1
+      assert:
         that:
-        - result.rowcount[0] == 1
+          - result.rowcount[0] == 1
 
-    - name: Try to set the same limits again in check mode
+    - name: Resource limits | Try to set the same limits again in check mode
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
@@ -69,11 +76,12 @@
       check_mode: yes
       register: result
 
-    - assert:
+    - name: Resource limits | Assert that set same limits again is not changed
+      assert:
         that:
           - result is not changed
 
-    - name: Try to set the same limits again in actual mode
+    - name: Resource limits | Try to set the same limits again in actual mode
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
@@ -84,11 +92,12 @@
           MAX_CONNECTIONS_PER_HOUR: 5
       register: result
 
-    - assert:
+    - name: Resource limits | Assert that set same limits again in actual mode is not changed
+      assert:
         that:
           - result is not changed
 
-    - name: Change limits
+    - name: Resource limits | Change limits
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
@@ -99,19 +108,24 @@
           MAX_CONNECTIONS_PER_HOUR: 5
       register: result
 
-    - assert:
+    - name: Resource limits | Assert limits changed
+      assert:
         that:
           - result is changed
 
-    - name: Check
+    - name: Resource limits | Get user limits
       mysql_query:
         <<: *mysql_params
         query: >
-          SELECT User FROM mysql.user WHERE User = '{{ user_name_1 }}' AND Host = 'localhost'
-          AND max_questions = 5 AND max_connections = 5
+          SELECT User FROM mysql.user
+          WHERE User = '{{ user_name_1 }}'
+          AND Host = 'localhost'
+          AND max_questions = 5
+          AND max_connections = 5
       register: result
 
-    - assert:
+    - name: Resource limits | Assert limit row count
+      assert:
         that:
           - result.rowcount[0] == 1
 
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_revoke_only_grant.yml b/tests/integration/targets/test_mysql_user/tasks/test_revoke_only_grant.yml
new file mode 100644
index 0000000..de0fc62
--- /dev/null
+++ b/tests/integration/targets/test_mysql_user/tasks/test_revoke_only_grant.yml
@@ -0,0 +1,50 @@
+---
+- vars:
+    mysql_parameters: &mysql_params
+      login_user: '{{ mysql_user }}'
+      login_password: '{{ mysql_password }}'
+      login_host: '{{ mysql_host }}'
+      login_port: '{{ mysql_primary_port }}'
+  block:
+    - include: utils/remove_user.yml user_name={{ user_name_1 }}
+
+    - name: Revoke only grants | Create user with two grants
+      mysql_user:
+        <<: *mysql_params
+        name: "{{ user_name_1 }}"
+        password: "{{ user_password_1 }}"
+        update_password: on_create
+        priv: '*.*:SELECT,GRANT'
+
+    - name: Revoke only grants | Revoke grant priv from db_user1
+      register: result
+      mysql_user:
+        <<: *mysql_params
+        name: "{{ user_name_1 }}"
+        password: "{{ user_password_1 }}"
+        update_password: on_create
+        priv: '*.*:SELECT'
+
+    - name: Revoke only grants | Assert that db_user1 only have one priv left
+      assert:
+        that:
+          - result is not failed
+          - result is changed
+
+    - name: Revoke only grants | Update db_user1 again to test idempotence
+      register: result
+      mysql_user:
+        <<: *mysql_params
+        name: "{{ user_name_1 }}"
+        password: "{{ user_password_1 }}"
+        update_password: on_create
+        priv: '*.*:SELECT'
+
+    - name: Revoke only grants | Assert that task is idempotent
+      assert:
+        that:
+          - result is succeeded
+          - result is not changed
+
+  always:
+    - include: utils/remove_user.yml user_name={{ user_name_1 }}
diff --git a/tests/integration/targets/test_mysql_user/tasks/tls_requirements.yml b/tests/integration/targets/test_mysql_user/tasks/test_tls_requirements.yml
similarity index 57%
rename from tests/integration/targets/test_mysql_user/tasks/tls_requirements.yml
rename to tests/integration/targets/test_mysql_user/tasks/test_tls_requirements.yml
index 7bf142e..f85ae3b 100644
--- a/tests/integration/targets/test_mysql_user/tasks/tls_requirements.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/test_tls_requirements.yml
@@ -3,26 +3,12 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
 
-    # ============================================================
-    - name: find out the database version
-      mysql_info:
-        <<: *mysql_params
-        filter: version
-      register: db_version
-
-    - name: Drop mysql user {{ item }} if exists
-      mysql_user:
-        <<: *mysql_params
-        name: '{{ item }}'
-        state: absent
-      with_items: ['{{ user_name_1 }}', '{{ user_name_2 }}', '{{ user_name_3 }}']
-
-    - name: create user with TLS requirements in check mode (expect changed=true)
+    - name: Tls reqs | Create user with TLS requirements in check mode (expect changed=true)
       mysql_user:
         <<: *mysql_params
         name: "{{ user_name_1 }}"
@@ -32,14 +18,14 @@
       check_mode: yes
       register: result
 
-    - name: Assert check mode user create reports changed state
+    - name: Tls reqs | Assert check mode user create reports changed state
       assert:
         that:
           - result is changed
 
-    - include: assert_no_user.yml user_name={{user_name_1}}
+    - include: utils/assert_no_user.yml user_name={{user_name_1}}
 
-    - name: create user with TLS requirements state=present (expect changed=true)
+    - name: Tls reqs | Create user with TLS requirements state=present (expect changed=true)
       mysql_user:
         <<: *mysql_params
         name: '{{ item[0] }}'
@@ -55,45 +41,49 @@
             issuer: '/CN=org/O=MyDom, Inc./C=US/ST=Oregon/L=Portland'
 
     - block:
-      - name: retrieve TLS requirements for users in old database version
+      - name: Tls reqs | Retrieve TLS requirements for users in old database version
         command: "{{ mysql_command }} -L -N -s -e \"SHOW GRANTS for '{{ item }}'@'localhost'\""
         register: old_result
         with_items: ['{{ user_name_1 }}', '{{ user_name_2 }}', '{{ user_name_3 }}']
 
-      - name: set old database separator
+      - name: Tls reqs | Set old database separator
         set_fact:
           separator: '\n'
       # Semantically: when mysql version <= 5.6 or MariaDB version <= 10.1
-      when: db_version.version.major <= 5 and db_version.version.minor <= 6 or db_version.version.major == 10 and db_version.version.minor < 2
+      when:
+        - (db_engine == 'mysql' and db_version is version('5.6', '<='))
+          or (db_engine == 'mariadb' and db_version is version('10.1', '<='))
 
     - block:
-      - name: retrieve TLS requirements for users in new database version
+      - name: Tls reqs | Retrieve TLS requirements for users in new database version
         command: "{{ mysql_command }} -L -N -s -e \"SHOW CREATE USER '{{ item }}'@'localhost'\""
         register: new_result
         with_items: ['{{ user_name_1 }}', '{{ user_name_2 }}', '{{ user_name_3 }}']
 
-      - name: set new database separator
+      - name: Tls reqs | Set new database separator
         set_fact:
           separator: 'PASSWORD'
       # Semantically: when mysql version >= 5.7 or MariaDB version >= 10.2
-      when: db_version.version.major == 5 and db_version.version.minor >= 7 or db_version.version.major > 5 and db_version.version.major < 10  or db_version.version.major == 10 and db_version.version.minor >= 2
+      when:
+        - (db_engine == 'mysql' and db_version is version('5.7', '>='))
+          or (db_engine == 'mariadb' and db_version is version('10.2', '>='))
 
     - block:
-      - name: assert user1 TLS requirements
+      - name: Tls reqs | Assert user1 TLS requirements
         assert:
           that:
             - "'SSL' in reqs"
         vars:
           - reqs: "{{((old_result.results[0] is skipped | ternary(new_result, old_result)).results | selectattr('item', 'contains', user_name_1) | first).stdout.split('REQUIRE')[1].split(separator)[0].strip()}}"
 
-      - name: assert user2 TLS requirements
+      - name: Tls reqs | Assert user2 TLS requirements
         assert:
           that:
             - "'X509' in reqs"
         vars:
           - reqs: "{{((old_result.results[0] is skipped | ternary(new_result, old_result)).results | selectattr('item', 'contains', user_name_2) | first).stdout.split('REQUIRE')[1].split(separator)[0].strip()}}"
 
-      - name: assert user3 TLS requirements
+      - name: Tls reqs | Assert user3 TLS requirements
         assert:
           that:
             - "'/CN=alice/O=MyDom, Inc./C=US/ST=Oregon/L=Portland' in (reqs | select('contains', 'SUBJECT') | first)"
@@ -104,7 +94,7 @@
       # CentOS 6 uses an older version of jinja that does not provide the selectattr filter.
       when: ansible_distribution != 'CentOS' or ansible_distribution_major_version != '6'
 
-    - name: modify user with TLS requirements state=present in check mode (expect changed=true)
+    - name: Tls reqs | Modify user with TLS requirements state=present in check mode (expect changed=true)
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
@@ -114,28 +104,32 @@
       check_mode: yes
       register: result
 
-    - name: Assert check mode user update reports changed state
+    - name: Tls reqs | Assert check mode user update reports changed state
       assert:
         that:
           - result is changed
 
-    - name: retrieve TLS requirements for users in old database version
+    - name: Tls reqs | Retrieve TLS requirements for users in old database version
       command: "{{ mysql_command }} -L -N -s -e \"SHOW GRANTS for '{{ user_name_1 }}'@'localhost'\""
       register: old_result
-      when: db_version.version.major <= 5 and db_version.version.minor <= 6 or db_version.version.major == 10 and db_version.version.minor < 2
+      when:
+        - (db_engine == 'mysql' and db_version is version('5.6', '<='))
+          or (db_engine == 'mariadb' and db_version is version('10.2', '<'))
 
-    - name: retrieve TLS requirements for users in new database version
+    - name: Tls reqs | Retrieve TLS requirements for users in new database version
       command: "{{ mysql_command }} -L -N -s -e \"SHOW CREATE USER '{{ user_name_1 }}'@'localhost'\""
       register: new_result
-      when: db_version.version.major == 5 and db_version.version.minor >= 7 or db_version.version.major > 5 and db_version.version.major < 10  or db_version.version.major == 10 and db_version.version.minor >= 2
+      when:
+        - (db_engine == 'mysql' and db_version is version('5.7', '>='))
+          or (db_engine == 'mariadb' and db_version is version('10.2', '>='))
 
-    - name: assert user1 TLS requirements was not changed
+    - name: Tls reqs | Assert user1 TLS requirements was not changed
       assert:
         that: "'SSL' in reqs"
       vars:
         - reqs: "{{(old_result is skipped | ternary(new_result, old_result)).stdout.split('REQUIRE')[1].split(separator)[0].strip()}}"
 
-    - name: modify user with TLS requirements state=present (expect changed=true)
+    - name: Tls reqs | Modify user with TLS requirements state=present (expect changed=true)
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
@@ -143,45 +137,49 @@
         tls_requires:
           X509:
 
-    - name: retrieve TLS requirements for users in old database version
+    - name: Tls reqs | Retrieve TLS requirements for users in old database version
       command: "{{ mysql_command }} -L -N -s -e \"SHOW GRANTS for '{{ user_name_1 }}'@'localhost'\""
       register: old_result
-      when: db_version.version.major <= 5 and db_version.version.minor <= 6 or db_version.version.major == 10 and db_version.version.minor < 2
+      when:
+        - (db_engine == 'mysql' and db_version is version('5.6', '<='))
+          or (db_engine == 'mariadb' and db_version is version('10.2', '<'))
 
-    - name: retrieve TLS requirements for users in new database version
+    - name: Tls reqs | Retrieve TLS requirements for users in new database version
       command: "{{ mysql_command }} -L -N -s -e \"SHOW CREATE USER '{{ user_name_1 }}'@'localhost'\""
       register: new_result
-      when: db_version.version.major == 5 and db_version.version.minor >= 7 or db_version.version.major > 5 and db_version.version.major < 10  or db_version.version.major == 10 and db_version.version.minor >= 2
+      when:
+        - (db_engine == 'mysql' and db_version is version('5.7', '>='))
+          or (db_engine == 'mariadb' and db_version is version('10.2', '>='))
 
-    - name: assert user1 TLS requirements
+    - name: Tls reqs | Assert user1 TLS requirements
       assert:
         that: "'X509' in reqs"
       vars:
         - reqs: "{{(old_result is skipped | ternary(new_result, old_result)).stdout.split('REQUIRE')[1].split(separator)[0].strip()}}"
 
-    - name: remove TLS requirements from user (expect changed=true)
+    - name: Tls reqs | Remove TLS requirements from user (expect changed=true)
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
         password: '{{ user_password_1 }}'
         tls_requires:
 
-    - name: retrieve TLS requirements for users
+    - name: Tls reqs | Retrieve TLS requirements for users
       command: "{{ mysql_command }} -L -N -s -e \"SHOW CREATE USER '{{ user_name_1 }}'@'localhost'\""
       register: result
 
-    - name: assert user1 TLS requirements
+    - name: Tls reqs | Assert user1 TLS requirements
       assert:
         that: "'REQUIRE ' not in result.stdout or 'REQUIRE NONE' in result.stdout"
 
-    - include: remove_user.yml user_name={{user_name_1}} user_password={{ user_password_1 }}
+    - include: utils/remove_user.yml user_name={{user_name_1}}
 
-    - include: remove_user.yml user_name={{user_name_2}} user_password={{ user_password_1 }}
+    - include: utils/remove_user.yml user_name={{user_name_2}}
 
-    - include: remove_user.yml user_name={{user_name_3}} user_password={{ user_password_1 }}
+    - include: utils/remove_user.yml user_name={{user_name_3}}
 
-    - include: assert_no_user.yml user_name={{user_name_1}}
+    - include: utils/assert_no_user.yml user_name={{user_name_1}}
 
-    - include: assert_no_user.yml user_name={{user_name_2}}
+    - include: utils/assert_no_user.yml user_name={{user_name_2}}
 
-    - include: assert_no_user.yml user_name={{user_name_3}}
+    - include: utils/assert_no_user.yml user_name={{user_name_3}}
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml b/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml
new file mode 100644
index 0000000..428c1ef
--- /dev/null
+++ b/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml
@@ -0,0 +1,129 @@
+---
+# Tests scenarios for both plaintext and encrypted user passwords.
+
+- vars:
+    mysql_parameters:
+      login_user: '{{ mysql_user }}'
+      login_password: '{{ mysql_password }}'
+      login_host: '{{ mysql_host }}'
+      login_port: '{{ mysql_primary_port }}'
+    test_password1: kbB9tcx5WOGVGfzV
+    test_password1_hash: '*AF6A7F9D038475C17EE46564F154104877EE5037'
+    test_password2: XBYjpHmjIctMxl1y
+    test_password2_hash: '*9E22D1B35C68BDDF398B8F28AE482E5A865BAC0A'
+    test_password3: tem33JfR5Yx98BB
+    test_password3_hash: '*C7E7C2710702F20336F8D93BC0670C8FB66BDBC7'
+
+
+  block:
+    - include_tasks: utils/assert_user_password.yml
+      vars:
+        username: "{{ item.username }}"
+        host: "%"
+        update_password: "{{ item.update_password }}"
+        password: "{{ test_password1 }}"
+        expect_change: "{{ item.expect_change }}"
+        expect_password_change: "{{ item.expect_change }}"
+        expect_password_hash: "{{ test_password1_hash }}"
+      loop:
+        # all variants set the password when nothing exists
+        - username: test1
+          update_password: always
+          expect_change: true
+        - username: test2
+          update_password: on_create
+          expect_change: true
+        - username: test3
+          update_password: on_new_username
+          expect_change: true
+
+        # assert idempotency
+        - username: test1
+          update_password: always
+          expect_change: false
+        - username: test2
+          update_password: on_create
+          expect_change: false
+        - username: test3
+          update_password: on_new_username
+          expect_change: false
+
+    # same user, new password
+    - include_tasks: utils/assert_user_password.yml
+      vars:
+        username: "{{ item.username }}"
+        host: "%"
+        update_password: "{{ item.update_password }}"
+        password: "{{ test_password2 }}"
+        expect_change: "{{ item.expect_change }}"
+        expect_password_change: "{{ item.expect_change }}"
+        expect_password_hash: "{{ item.expect_password_hash }}"
+      loop:
+        - username: test1
+          update_password: always
+          expect_change: true
+          expect_password_hash: "{{ test_password2_hash }}"
+        - username: test2
+          update_password: on_create
+          expect_change: false
+          expect_password_hash: "{{ test_password1_hash }}"
+        - username: test3
+          update_password: on_new_username
+          expect_change: false
+          expect_password_hash: "{{ test_password1_hash }}"
+
+    # new user, new password
+    - include_tasks: utils/assert_user_password.yml
+      vars:
+        username: "{{ item.username }}"
+        host: '::1'
+        update_password: "{{ item.update_password }}"
+        password: "{{ item.password }}"
+        expect_change: "{{ item.expect_change }}"
+        expect_password_change: "{{ item.expect_password_change }}"
+        expect_password_hash: "{{ item.expect_password_hash }}"
+      loop:
+        - username: test1
+          update_password: always
+          expect_change: true
+          expect_password_change: true
+          password: "{{ test_password1 }}"
+          expect_password_hash: "{{ test_password1_hash }}"
+        - username: test2
+          update_password: on_create
+          expect_change: true
+          expect_password_change: true
+          password: "{{ test_password2 }}"
+          expect_password_hash: "{{ test_password2_hash }}"
+        - username: test3
+          update_password: on_new_username
+          expect_change: true
+          expect_password_change: false
+          password: "{{ test_password2 }}"
+          expect_password_hash: "{{ test_password1_hash }}"
+
+        # prepare for next test: ensure all users have varying passwords
+        - username: test3
+          update_password: always
+          expect_change: true
+          expect_password_change: true
+          password: "{{ test_password2 }}"
+          expect_password_hash: "{{ test_password2_hash }}"
+
+    # another new user, another new password and multiple existing users with varying passwords
+    - include_tasks: utils/assert_user_password.yml
+      vars:
+        username: "{{ item.username }}"
+        host: '2001:db8::1'
+        update_password: "{{ item.update_password }}"
+        password: "{{ test_password3 }}"
+        expect_change: true
+        expect_password_change: true
+        expect_password_hash: "{{ test_password3_hash }}"
+      loop:
+        - username: test1
+          update_password: always
+        - username: test2
+          update_password: on_create
+        - username: test3
+          update_password: on_new_username
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_user_grants_with_roles_applied.yml b/tests/integration/targets/test_mysql_user/tasks/test_user_grants_with_roles_applied.yml
index 7af3890..bd6c4e5 100644
--- a/tests/integration/targets/test_mysql_user/tasks/test_user_grants_with_roles_applied.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/test_user_grants_with_roles_applied.yml
@@ -1,31 +1,30 @@
+---
 # https://github.com/ansible-collections/community.mysql/issues/231
 - vars:
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
-    - name: Get server version
-      mysql_info:
-        <<: *mysql_params
-      register: srv
 
-    # Skip unsupported versions
-    - meta: end_play
-      when: srv['version']['major'] < 8
+    - name: User grants with roles applied | Skip unsupported versions
+      meta: end_play
+      when:
+        - db_engine == 'mysql'
+        - db_version is version('8.0.0', '<')
 
-    - name: Create test databases
+    - name: User grants with roles applied | Create test databases
       mysql_db:
         <<: *mysql_params
         name: '{{ item }}'
         state: present
       loop:
-      - data1
-      - data2
+        - data1
+        - data2
 
-    - name: Create user with privileges
+    - name: User grants with roles applied | Create user with privileges
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_3 }}'
@@ -35,7 +34,7 @@
           "data2.*": "SELECT"
         state: present
 
-    - name: Run command to show privileges for user (expect privileges in stdout)
+    - name: User grants with roles applied | Run command to show privileges for user (expect privileges in stdout)
       command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_3 }}'@'localhost'\""
       register: result
 
@@ -56,7 +55,7 @@
         <<: *mysql_params
         query: 'GRANT test231 TO {{ user_name_3 }}@localhost'
 
-    - name: Try to change privs
+    - name: User grants with roles applied | Try to change privs
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_3 }}'
@@ -65,11 +64,11 @@
           "data2.*": "INSERT"
         state: present
 
-    - name: Run command to show privileges for user (expect privileges in stdout)
+    - name: User grants with roles applied | Run command to show privileges for user (expect privileges in stdout)
       command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name_3 }}'@'localhost'\""
       register: result
 
-    - name: Assert user has giving privileges
+    - name: User grants with roles applied | Assert user has giving privileges
       assert:
         that:
           - "'GRANT INSERT ON `data1`.*' in result.stdout"
@@ -77,20 +76,16 @@
 
     ##########
     # Clean up
-    - name: Drop test databases
+    - name: User grants with roles applied | Drop test databases
       mysql_db:
         <<: *mysql_params
         name: '{{ item }}'
-        state: present
-      loop:
-      - data1
-      - data2
-
-    - name: Drop test user
-      mysql_user:
-        <<: *mysql_params
-        name: '{{ user_name_3 }}'
         state: absent
+      loop:
+        - data1
+        - data2
+
+    - include: utils/remove_user.yml user_name={{ user_name_3 }}
 
     - name: Drop test role
       mysql_query:
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_user_password.yml b/tests/integration/targets/test_mysql_user/tasks/test_user_password.yml
index 57d8d29..d98c92c 100644
--- a/tests/integration/targets/test_mysql_user/tasks/test_user_password.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/test_user_password.yml
@@ -1,10 +1,11 @@
+---
 # Tests scenarios for both plaintext and encrypted user passwords.
 
 - vars:
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
     test_user_name: 'test_user_password'
     initial_password: 'a5C8SN*DBa0%a75sGz'
@@ -20,23 +21,24 @@
     # Test setting plaintext password and changing it.
     #
 
-    - name: Create user with initial password
+    - name: Password | Create user with initial password
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         password: '{{ initial_password }}'
         priv: '{{ test_default_priv }}'
         state: present
       register: result
 
-    - name: Assert that a change occurred because the user was added
+    - name: Password | Assert that a change occurred because the user was added
       assert:
         that:
           - result is changed
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Get the MySQL version using the newly created used creds
+    - name: Password | Get the MySQL version using the newly created used creds
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ initial_password }}'
@@ -46,43 +48,45 @@
       register: result
       ignore_errors: true
 
-    - name: Assert that mysql_info was successful
+    - name: Password | Assert that mysql_info was successful
       assert:
         that:
           - result is succeeded
 
-    - name: Run mysql_user again without any changes
+    - name: Password | Run mysql_user again without any changes
       mysql_user:
         <<: *mysql_params
-        name: '{{ test_user_name }}'
-        password: '{{ initial_password }}'
-        priv: '{{ test_default_priv }}'
+        name: "{{ test_user_name }}"
+        host: "%"
+        password: "{{ initial_password }}"
+        priv: "{{ test_default_priv }}"
         state: present
       register: result
 
-    - name: Assert that there weren't any changes because username/password didn't change
+    - name: Password | Assert that there weren't any changes because username/password didn't change
       assert:
         that:
           - result is not changed
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Update the user password
+    - name: Password | Update the user password
       mysql_user:
         <<: *mysql_params
-        name: '{{ test_user_name }}'
-        password: '{{ new_password }}'
+        name: "{{ test_user_name }}"
+        host: "%"
+        password: "{{ new_password }}"
         state: present
       register: result
 
-    - name: Assert that a change occurred because the password was updated
+    - name: Password | Assert that a change occurred because the password was updated
       assert:
         that:
           - result is changed
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Get the MySQL version data using the original password (should fail)
+    - name: Password | Get the MySQL version data using the original password (should fail)
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ initial_password }}'
@@ -92,12 +96,12 @@
       register: result
       ignore_errors: true
 
-    - name: Assert that the mysql_info module failed because we used the old password
+    - name: Password | Assert that the mysql_info module failed because we used the old password
       assert:
         that:
           - result is failed
 
-    - name: Get the MySQL version data using the new password (should work)
+    - name: Password | Get the MySQL version data using the new password (should work)
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ new_password }}'
@@ -107,19 +111,19 @@
       register: result
       ignore_errors: true
 
-    - name: Assert that the mysql_info module succeeded because we used the new password
+    - name: Password | Assert that the mysql_info module succeeded because we used the new password
       assert:
         that:
           - result is succeeded
 
     # Cleanup
-    - include: remove_user.yml user_name={{ test_user_name }} user_password={{ new_password }}
+    - include: utils/remove_user.yml user_name={{ test_user_name }}
 
     # ============================================================
     # Test setting a plaintext password and then the same password encrypted to ensure there isn't a change detected.
     #
 
-    - name: Create user with initial password
+    - name: Password | Create user with initial password
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
@@ -128,14 +132,14 @@
         state: present
       register: result
 
-    - name: Assert that a change occurred because the user was added
+    - name: Password | Assert that a change occurred because the user was added
       assert:
         that:
           - result is changed
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=localhost priv={{ test_default_priv_type }}
 
-    - name: Pass in the same password as before, but in the encrypted form (no change expected)
+    - name: Password | Pass in the same password as before, but in the encrypted form (no change expected)
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
@@ -145,36 +149,37 @@
         state: present
       register: result
 
-    - name: Assert that there weren't any changes because username/password didn't change
+    - name: Password | Assert that there weren't any changes because username/password didn't change
       assert:
         that:
           - result is not changed
 
     # Cleanup
-    - include: remove_user.yml user_name={{ test_user_name }} user_password={{ new_password }}
+    - include: utils/remove_user.yml user_name={{ test_user_name }}
 
     # ============================================================
     # Test setting an encrypted password and then the same password in plaintext to ensure there isn't a change.
     #
 
-    - name: Create user with initial password
+    - name: Password | Create user with initial password
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: "%"
         password: '{{ initial_password_encrypted }}'
         encrypted: yes
         priv: '{{ test_default_priv }}'
         state: present
       register: result
 
-    - name: Assert that a change occurred because the user was added
+    - name: Password | Assert that a change occurred because the user was added
       assert:
         that:
           - result is changed
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Get the MySQL version data using the new creds
+    - name: Password | Get the MySQL version data using the new creds
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ initial_password }}'
@@ -184,60 +189,62 @@
       register: result
       ignore_errors: true
 
-    - name: Assert that the mysql_info module succeeded because we used the new password
+    - name: Password | Assert that the mysql_info module succeeded because we used the new password
       assert:
         that:
           - result is succeeded
 
-    - name: Pass in the same password as before, but in the encrypted form (no change expected)
+    - name: Password | Pass in the same password as before, but in the encrypted form (no change expected)
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: "%"
         password: '{{ initial_password }}'
         state: present
       register: result
 
-    - name: Assert that there weren't any changes because username/password didn't change
+    - name: Password | Assert that there weren't any changes because username/password didn't change
       assert:
         that:
           - result is not changed
 
     # Cleanup
-    - include: remove_user.yml user_name={{ test_user_name }} user_password={{ new_password }}
+    - include: utils/remove_user.yml user_name={{ test_user_name }}
 
     # ============================================================
     # Test setting an empty password.
     #
 
-    - name: Create user with empty password
+    - name: Password | Create user with empty password
       mysql_user:
         <<: *mysql_params
-        name: '{{ test_user_name }}'
-        priv: '{{ test_default_priv }}'
+        name: "{{ test_user_name }}"
+        host: "%"
+        priv: "{{ test_default_priv }}"
         state: present
       register: result
 
-    - name: Assert that a change occurred because the user was added
+    - name: Password | Assert that a change occurred because the user was added
       assert:
         that:
           - result is changed
 
-    - name: Get the MySQL version using an empty password for the newly created user
+    - name: Password | Get the MySQL version using an empty password for the newly created user
       mysql_info:
-        login_user: '{{ test_user_name }}'
-        login_password: ''
-        login_host: '{{ mysql_host }}'
-        login_port: '{{ mysql_primary_port }}'
+        login_user: "{{ test_user_name }}"
+        login_password: ""
+        login_host: "{{ mysql_host }}"
+        login_port: "{{ mysql_primary_port }}"
         filter: version
       register: result
       ignore_errors: true
 
-    - name: Assert that mysql_info was successful
+    - name: Password | Assert that mysql_info was successful
       assert:
         that:
           - result is succeeded
 
-    - name: Get the MySQL version using an non-empty password (should fail)
+    - name: Password | Get the MySQL version using an non-empty password (should fail)
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: 'some_password'
@@ -247,23 +254,24 @@
       register: result
       ignore_errors: true
 
-    - name: Assert that mysql_info failed
+    - name: Password | Assert that mysql_info failed
       assert:
         that:
           - result is failed
 
-    - name: Update the user without changing the password
+    - name: Password | Update the user without changing the password
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: "%"
         priv: '{{ test_default_priv }}'
         state: present
       register: result
 
-    - name: Assert that the user wasn't changed because the password is still empty
+    - name: Password | Assert that the user wasn't changed because the password is still empty
       assert:
         that:
           - result is not changed
 
     # Cleanup
-    - include: remove_user.yml user_name={{ test_user_name }} user_password=''
+    - include: utils/remove_user.yml user_name={{ test_user_name }}
diff --git a/tests/integration/targets/test_mysql_user/tasks/test_user_plugin_auth.yml b/tests/integration/targets/test_mysql_user/tasks/test_user_plugin_auth.yml
index 264d8bd..8d7740b 100644
--- a/tests/integration/targets/test_mysql_user/tasks/test_user_plugin_auth.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/test_user_plugin_auth.yml
@@ -1,10 +1,11 @@
+---
 # Test user plugin auth scenarios.
 
 - vars:
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
     test_user_name: 'test_user_plugin_auth'
     test_plugin_type: 'mysql_native_password'
@@ -21,33 +22,34 @@
     # Test plugin auth initially setting a hash and then changing to a different hash.
     #
 
-    - name: Create user with plugin auth (with hash string)
+    - name: Plugin auth | Create user with plugin auth (with hash string)
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         plugin_hash_string: '{{ test_plugin_hash }}'
         priv: '{{ test_default_priv }}'
       register: result
 
-    - name: Get user information
-      command: "{{ mysql_command }} -e \"SELECT user, host, plugin FROM mysql.user WHERE user = '{{ test_user_name }}' and host = 'localhost'\""
+    - name: Plugin auth | Get user information (with hash string)
+      command: "{{ mysql_command }} -e \"SELECT user, host, plugin FROM mysql.user WHERE user = '{{ test_user_name }}' and host = '%'\""
       register: show_create_user
 
-    - name: Check that the module made a change
+    - name: Plugin auth | Check that the module made a change (with hash string)
       assert:
         that:
           - result is changed
 
-    - name: Check that the expected plugin type is set
+    - name: Plugin auth | Check that the expected plugin type is set (with hash string)
       assert:
         that:
           - "'{{ test_plugin_type }}' in show_create_user.stdout"
-      when: install_type == 'mysql' or (install_type == 'mariadb' and mariadb_version is version('10.3', '>='))
+      when: db_engine == 'mysql' or (db_engine == 'mariadb' and db_version is version('10.3', '>='))
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Get the MySQL version using the newly created creds
+    - name: Plugin auth | Get the MySQL version using the newly created creds
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ test_plugin_auth_string }}'
@@ -56,27 +58,28 @@
         filter: version
       register: result
 
-    - name: Assert that mysql_info was successful
+    - name: Plugin auth | Assert that mysql_info was successful
       assert:
         that:
           - result is succeeded
 
-    - name: Update the user with a different hash
+    - name: Plugin auth | Update the user with a different hash
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         plugin_hash_string: '{{ test_plugin_new_hash }}'
       register: result
 
-    - name: Check that the module makes the change because the hash changed
+    - name: Plugin auth | Check that the module makes the change because the hash changed
       assert:
         that:
           - result is changed
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Getting the MySQL info with the new password should work
+    - name: Plugin auth | Getting the MySQL info with the new password should work
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ test_plugin_new_auth_string }}'
@@ -85,45 +88,46 @@
         filter: version
       register: result
 
-    - name: Assert that mysql_info was successful
+    - name: Plugin auth | Assert that mysql_info was successful
       assert:
         that:
           - result is succeeded
 
     # Cleanup
-    - include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_new_auth_string }}
+    - include: utils/remove_user.yml user_name={{ test_user_name }}
 
     # ============================================================
     # Test plugin auth initially setting a hash and then switching to a plaintext auth string.
     #
 
-    - name: Create user with plugin auth (with hash string)
+    - name: Plugin auth | Create user with plugin auth (with hash string)
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         plugin_hash_string: '{{ test_plugin_hash }}'
         priv: '{{ test_default_priv }}'
       register: result
 
-    - name: Get user information
-      command: "{{ mysql_command }} -e \"SELECT user, host, plugin FROM mysql.user WHERE user = '{{ test_user_name }}' and host = 'localhost'\""
+    - name: Plugin auth | Get user information
+      command: "{{ mysql_command }} -e \"SELECT user, host, plugin FROM mysql.user WHERE user = '{{ test_user_name }}' and host = '%'\""
       register: show_create_user
 
-    - name: Check that the module made a change
+    - name: Plugin auth | Check that the module made a change (with hash string)
       assert:
         that:
           - result is changed
 
-    - name: Check that the expected plugin type is set
+    - name: Plugin auth | Check that the expected plugin type is set (with hash string)
       assert:
         that:
           - "'{{ test_plugin_type }}' in show_create_user.stdout"
-      when: install_type == 'mysql' or (install_type == 'mariadb' and mariadb_version is version('10.3', '>='))
+      when: db_engine == 'mysql' or (db_engine == 'mariadb' and db_version is version('10.3', '>='))
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Get the MySQL version using the newly created creds
+    - name: Plugin auth | Get the MySQL version using the newly created creds
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ test_plugin_auth_string }}'
@@ -132,43 +136,45 @@
         filter: version
       register: result
 
-    - name: Assert that mysql_info was successful
+    - name: Plugin auth | Assert that mysql_info was successful
       assert:
         that:
           - result is succeeded
 
-    - name: Update the user with the same hash (no change expected)
+    - name: Plugin auth | Update the user with the same hash (no change expected)
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         plugin_hash_string: '{{ test_plugin_hash }}'
       register: result
 
     # FIXME: on mariadb 10.2 there's always a change
-    - name: Check that the module doesn't make a change when the same hash is passed in
+    - name: Plugin auth | Check that the module doesn't make a change when the same hash is passed in
       assert:
         that:
           - result is not changed
-      when: install_type == 'mysql' or (install_type == 'mariadb' and mariadb_version is version('10.3', '>='))
+      when: db_engine == 'mysql' or (db_engine == 'mariadb' and db_version is version('10.3', '>='))
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Change the user using the same plugin, but switch to the same auth string in plaintext form
+    - name: Plugin auth | Change the user using the same plugin, but switch to the same auth string in plaintext form
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         plugin_auth_string: '{{ test_plugin_auth_string }}'
       register: result
 
     # Expecting a change is currently by design (see comment in source).
-    - name: Check that the module did not change the password
+    - name: Plugin auth | Check that the module did not change the password
       assert:
         that:
           - result is changed
 
-    - name: Getting the MySQL info should still work
+    - name: Plugin auth | Getting the MySQL info should still work
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ test_plugin_auth_string }}'
@@ -177,45 +183,46 @@
         filter: version
       register: result
 
-    - name: Assert that mysql_info was successful
+    - name: Plugin auth | Assert that mysql_info was successful
       assert:
         that:
           - result is succeeded
 
     # Cleanup
-    - include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_auth_string }}
+    - include: utils/remove_user.yml user_name={{ test_user_name }}
 
     # ============================================================
     # Test plugin auth initially setting a plaintext auth string and then switching to a hash.
     #
 
-    - name: Create user with plugin auth (with auth string)
+    - name: Plugin auth | Create user with plugin auth (with auth string)
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         plugin_auth_string: '{{ test_plugin_auth_string }}'
         priv: '{{ test_default_priv }}'
       register: result
 
-    - name: Get user information
-      command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
+    - name: Plugin auth | Get user information(with auth string)
+      command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'%'\""
       register: show_create_user
 
-    - name: Check that the module made a change
+    - name: Plugin auth | Check that the module made a change (with auth string)
       assert:
         that:
           - result is changed
 
-    - name: Check that the expected plugin type is set
+    - name: Plugin auth | Check that the expected plugin type is set (with auth string)
       assert:
         that:
-          - "'{{ test_plugin_type }}' in show_create_user.stdout"
-      when: install_type == 'mysql' or (install_type == 'mariadb' and mariadb_version is version('10.3', '>='))
+          - test_plugin_type in show_create_user.stdout
+      when: db_engine == 'mysql' or (db_engine == 'mariadb' and db_version is version('10.3', '>='))
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Get the MySQL version using the newly created creds
+    - name: Plugin auth | Get the MySQL version using the newly created creds
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ test_plugin_auth_string }}'
@@ -224,42 +231,44 @@
         filter: version
       register: result
 
-    - name: Assert that mysql_info was successful
+    - name: Plugin auth | Assert that mysql_info was successful
       assert:
         that:
           - result is succeeded
 
-    - name: Update the user with the same auth string
+    - name: Plugin auth | Update the user with the same auth string
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         plugin_auth_string: '{{ test_plugin_auth_string }}'
       register: result
 
     # This is the current expected behavior because there isn't a reliable way to hash the password in the mysql_user
     # module in order to be able to compare this password with the stored hash. See the source for more info.
-    - name: The module should detect a change even though the password is the same
+    - name: Plugin auth | The module should detect a change even though the password is the same
       assert:
         that:
           - result is changed
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Change the user using the same plugin, but switch to the same auth string in hash form
+    - name: Plugin auth | Change the user using the same plugin, but switch to the same auth string in hash form
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         plugin_hash_string: '{{ test_plugin_hash }}'
       register: result
 
-    - name: Check that the module did not change the password
+    - name: Plugin auth | Check that the module did not change the password
       assert:
         that:
           - result is not changed
 
-    - name: Get the MySQL version using the newly created creds
+    - name: Plugin auth | Get the MySQL version using the newly created creds
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: '{{ test_plugin_auth_string }}'
@@ -268,44 +277,45 @@
         filter: version
       register: result
 
-    - name: Assert that mysql_info was successful
+    - name: Plugin auth | Assert that mysql_info was successful
       assert:
         that:
           - result is succeeded
 
     # Cleanup
-    - include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_auth_string }}
+    - include: utils/remove_user.yml user_name={{ test_user_name }}
 
     # ============================================================
     # Test plugin auth with an empty auth string.
     #
 
-    - name: Create user with plugin auth (empty auth string)
+    - name: Plugin auth | Create user with plugin auth (empty auth string)
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         priv: '{{ test_default_priv }}'
       register: result
 
-    - name: Get user information
-      command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
+    - name: Plugin auth | Get user information (empty auth string)
+      command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'%'\""
       register: show_create_user
 
-    - name: Check that the module made a change
+    - name: Plugin auth | Check that the module made a change (empty auth string)
       assert:
         that:
           - result is changed
 
-    - name: Check that the expected plugin type is set
+    - name: Plugin auth | Check that the expected plugin type is set (empty auth string)
       assert:
         that:
           - "'{{ test_plugin_type }}' in show_create_user.stdout"
-      when: install_type == 'mysql' or (install_type == 'mariadb' and mariadb_version is version('10.3', '>='))
+      when: db_engine == 'mysql' or (db_engine == 'mariadb' and db_version is version('10.3', '>='))
 
-    - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+    - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=% priv={{ test_default_priv_type }}
 
-    - name: Get the MySQL version using an empty password for the newly created user
+    - name: Plugin auth | Get the MySQL version using an empty password for the newly created user
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: ''
@@ -315,12 +325,12 @@
       register: result
       ignore_errors: true
 
-    - name: Assert that mysql_info was successful
+    - name: Plugin auth | Assert that mysql_info was successful
       assert:
         that:
           - result is succeeded
 
-    - name: Get the MySQL version using an non-empty password (should fail)
+    - name: Plugin auth | Get the MySQL version using an non-empty password (should fail)
       mysql_info:
         login_user: '{{ test_user_name }}'
         login_password: 'some_password'
@@ -330,91 +340,92 @@
       register: result
       ignore_errors: true
 
-    - name: Assert that mysql_info failed
+    - name: Plugin auth | Assert that mysql_info failed
       assert:
         that:
           - result is failed
 
-    - name: Update the user without changing the auth mechanism
+    - name: Plugin auth | Update the user without changing the auth mechanism
       mysql_user:
         <<: *mysql_params
         name: '{{ test_user_name }}'
+        host: '%'
         plugin: '{{ test_plugin_type }}'
         state: present
       register: result
 
-    - name: Assert that the user wasn't changed because the auth string is still empty
+    - name: Plugin auth | Assert that the user wasn't changed because the auth string is still empty
       assert:
         that:
           - result is not changed
 
     # Cleanup
-    - include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_auth_string }}
+    - include: utils/remove_user.yml user_name={{ test_user_name }}
 
     # ============================================================
     # Test plugin auth switching from one type of plugin to another without an auth string or hash. The only other
     # plugins that are loaded by default are sha2*, but these aren't compatible with pymysql < 0.9, so skip these tests
     # for those versions.
     #
-    - name: Test plugin auth switching which doesn't work on pymysql < 0.9
+    - name: Plugin auth | Test plugin auth switching which doesn't work on pymysql < 0.9
       when:
         - >
-          connector_name is not search('pymysql')
+          connector_name != 'pymysql'
           or (
-            connector_name is search('pymysql')
-            and connector_ver is version('0.9', '>=')
+            connector_name == 'pymysql'
+            and connector_version is version('0.9', '>=')
           )
       block:
 
-      - name: Create user with plugin auth (empty auth string)
-        mysql_user:
-          <<: *mysql_params
-          name: '{{ test_user_name }}'
-          plugin: '{{ test_plugin_type }}'
-          priv: '{{ test_default_priv }}'
-        register: result
+        - name: Plugin auth | Create user with plugin auth (empty auth string)
+          mysql_user:
+            <<: *mysql_params
+            name: '{{ test_user_name }}'
+            plugin: '{{ test_plugin_type }}'
+            priv: '{{ test_default_priv }}'
+          register: result
 
-      - name: Get user information
-        command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
-        register: show_create_user
+        - name: Plugin auth | Get user information (empty auth string)
+          command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
+          register: show_create_user
 
-      - name: Check that the module made a change
-        assert:
-          that:
-            - result is changed
+        - name: Plugin auth | Check that the module made a change (empty auth string)
+          assert:
+            that:
+              - result is changed
 
-      - name: Check that the expected plugin type is set
-        assert:
-          that:
-            - "'{{ test_plugin_type }}' in show_create_user.stdout"
-        when: install_type == 'mysql' or (install_type == 'mariadb' and mariadb_version is version('10.3', '>='))
+        - name: Plugin auth | Check that the expected plugin type is set (empty auth string)
+          assert:
+            that:
+              - test_plugin_type in show_create_user.stdout
+          when: db_engine == 'mysql' or (db_engine == 'mariadb' and db_version is version('10.3', '>='))
 
-      - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+        - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=localhost priv={{ test_default_priv_type }}
 
-      - name: Switch user to sha256_password auth plugin
-        mysql_user:
-          <<: *mysql_params
-          name: '{{ test_user_name }}'
-          plugin: sha256_password
-          priv: '{{ test_default_priv }}'
-        register: result
+        - name: Plugin auth | Switch user to sha256_password auth plugin
+          mysql_user:
+            <<: *mysql_params
+            name: '{{ test_user_name }}'
+            plugin: sha256_password
+            priv: '{{ test_default_priv }}'
+          register: result
 
-      - name: Get user information
-        command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
-        register: show_create_user
+        - name: Plugin auth | Get user information (sha256_password)
+          command: "{{ mysql_command }} -e \"SHOW CREATE USER '{{ test_user_name }}'@'localhost'\""
+          register: show_create_user
 
-      - name: Check that the module made a change
-        assert:
-          that:
-            - result is changed
+        - name: Plugin auth | Check that the module made a change (sha256_password)
+          assert:
+            that:
+              - result is changed
 
-      - name: Check that the expected plugin type is set
-        assert:
-          that:
+        - name: Plugin auth | Check that the expected plugin type is set (sha256_password)
+          assert:
+            that:
               - "'sha256_password' in show_create_user.stdout"
-        when: install_type == 'mysql' or (install_type == 'mariadb' and mariadb_version is version('10.3', '>='))
+          when: db_engine == 'mysql' or (db_engine == 'mariadb' and db_version is version('10.3', '>='))
 
-      - include: assert_user.yml user_name={{ test_user_name }} priv={{ test_default_priv_type }}
+        - include: utils/assert_user.yml user_name={{ test_user_name }} user_host=localhost priv={{ test_default_priv_type }}
 
-      # Cleanup
-      - include: remove_user.yml user_name={{ test_user_name }} user_password={{ test_plugin_auth_string }}
+        # Cleanup
+        - include: utils/remove_user.yml user_name={{ test_user_name }}
diff --git a/tests/integration/targets/test_mysql_user/tasks/utils/assert_no_user.yml b/tests/integration/targets/test_mysql_user/tasks/utils/assert_no_user.yml
new file mode 100644
index 0000000..6fc4fbc
--- /dev/null
+++ b/tests/integration/targets/test_mysql_user/tasks/utils/assert_no_user.yml
@@ -0,0 +1,8 @@
+---
+- name: Utils | Assert no user | Query for user {{ user_name }}
+  command: "{{ mysql_command }} -e \"SELECT User FROM mysql.user where user='{{ user_name }}'\""
+  register: result
+
+- name: Utils | Assert no user | Assert mysql user is not present
+  assert:
+    that: user_name not in result.stdout
diff --git a/tests/integration/targets/test_mysql_user/tasks/utils/assert_user.yml b/tests/integration/targets/test_mysql_user/tasks/utils/assert_user.yml
new file mode 100644
index 0000000..e6bd23f
--- /dev/null
+++ b/tests/integration/targets/test_mysql_user/tasks/utils/assert_user.yml
@@ -0,0 +1,21 @@
+---
+
+- name: Utils | Assert user | Query for user {{ user_name }}
+  command: "{{ mysql_command }} -e \"SELECT user FROM mysql.user where user='{{ user_name }}'\""
+  register: result
+
+- name: Utils | Assert user | Assert user is present
+  assert:
+    that:
+      - user_name in result.stdout
+
+- name: Utils | Assert user | Query for privileges of user {{ user_name }}
+  command: "{{ mysql_command }} -e \"SHOW GRANTS FOR '{{ user_name }}'@'{{ user_host }}'\""
+  register: result
+  when: priv is defined
+
+- name: Utils | Assert user | Assert user has given privileges
+  ansible.builtin.assert:
+    that:
+      - "'GRANT {{ priv }} ON *.*' in result.stdout"
+  when: priv is defined
diff --git a/tests/integration/targets/test_mysql_user/tasks/assert_user_password.yml b/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password.yml
similarity index 73%
rename from tests/integration/targets/test_mysql_user/tasks/assert_user_password.yml
rename to tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password.yml
index ba045eb..d95e53b 100644
--- a/tests/integration/targets/test_mysql_user/tasks/assert_user_password.yml
+++ b/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password.yml
@@ -1,4 +1,5 @@
-- name: "applying user {{ username }}@{{ host }} with update_password={{ update_password }}"
+---
+- name: Utils | Assert user password | Apply update_password to {{ username }}
   mysql_user:
     login_user: '{{ mysql_parameters.login_user }}'
     login_password: '{{ mysql_parameters.login_password }}'
@@ -10,15 +11,18 @@
     password: "{{ password }}"
     update_password: "{{ update_password }}"
   register: result
-- name: assert a change occurred
+
+- name: Utils | Assert user password | Assert a change occurred
   assert:
     that:
       - "result.changed | bool == {{ expect_change }} | bool"
       - "result.password_changed == {{ expect_password_change }}"
-- name: query the user
+
+- name: Utils | Assert user password | Query user {{ username }}
   command: "{{ mysql_command }} -BNe \"SELECT plugin, authentication_string FROM mysql.user where user='{{ username }}' and host='{{ host }}'\""
   register: existing_user
-- name: assert the password is as set to expect_hash
+
+- name: Utils | Assert user password | Assert expect_hash is in user stdout
   assert:
     that:
       - "'mysql_native_password\t{{ expect_password_hash }}' in existing_user.stdout_lines"
diff --git a/tests/integration/targets/test_mysql_user/tasks/utils/create_user.yml b/tests/integration/targets/test_mysql_user/tasks/utils/create_user.yml
new file mode 100644
index 0000000..b255ec4
--- /dev/null
+++ b/tests/integration/targets/test_mysql_user/tasks/utils/create_user.yml
@@ -0,0 +1,12 @@
+---
+
+- name: Utils | Create user {{ user_name }}
+  mysql_user:
+    login_user: "{{ mysql_user }}"
+    login_password: "{{ mysql_password }}"
+    login_host: "{{ mysql_host }}"
+    login_port: "{{ mysql_primary_port }}"
+    name: "{{ user_name }}"
+    host: "{{ user_host | default(omit) }}"
+    password: "{{ user_password }}"
+    state: present
diff --git a/tests/integration/targets/test_mysql_user/tasks/utils/remove_user.yml b/tests/integration/targets/test_mysql_user/tasks/utils/remove_user.yml
new file mode 100644
index 0000000..473cece
--- /dev/null
+++ b/tests/integration/targets/test_mysql_user/tasks/utils/remove_user.yml
@@ -0,0 +1,12 @@
+---
+
+- name: Utils | Remove user {{ user_name }}
+  mysql_user:
+    login_user: "{{ mysql_user }}"
+    login_password: "{{ mysql_password }}"
+    login_host: "{{ mysql_host }}"
+    login_port: "{{ mysql_primary_port }}"
+    name: "{{ user_name }}"
+    host_all: true
+    state: absent
+  ignore_errors: true
diff --git a/tests/integration/targets/test_mysql_variables/defaults/main.yml b/tests/integration/targets/test_mysql_variables/defaults/main.yml
index 6d0e2ec..779eead 100644
--- a/tests/integration/targets/test_mysql_variables/defaults/main.yml
+++ b/tests/integration/targets/test_mysql_variables/defaults/main.yml
@@ -2,6 +2,7 @@
 # defaults file for test_mysql_variables
 mysql_user: root
 mysql_password: msandbox
+mysql_host: '{{ gateway_addr }}'
 mysql_primary_port: 3307
 
 user_name_1: 'db_user1'
diff --git a/tests/integration/targets/test_mysql_variables/meta/main.yml b/tests/integration/targets/test_mysql_variables/meta/main.yml
index f1174ff..01ee3db 100644
--- a/tests/integration/targets/test_mysql_variables/meta/main.yml
+++ b/tests/integration/targets/test_mysql_variables/meta/main.yml
@@ -1,2 +1,3 @@
+---
 dependencies:
-  - setup_mysql
+  - setup_controller
diff --git a/tests/integration/targets/test_mysql_variables/tasks/assert_var.yml b/tests/integration/targets/test_mysql_variables/tasks/assert_var.yml
index 96d196d..e64c5a7 100644
--- a/tests/integration/targets/test_mysql_variables/tasks/assert_var.yml
+++ b/tests/integration/targets/test_mysql_variables/tasks/assert_var.yml
@@ -1,3 +1,4 @@
+---
 # test code to assert variables in mysql_variables module
 # (c) 2014,  Wayne Rosario <wrosario@ansible.com>
 
@@ -19,16 +20,16 @@
 # ============================================================
 # Assert mysql variable name and value from mysql database
 #
-- name: assert output message changed value
+- name: Assert output message changed value
   assert:
     that:
       - "output.changed | bool == changed | bool"
 
-- name: run mysql command to show variable
+- name: Run mysql command to show variable
   command: "{{ mysql_command }} \"-e show variables like '{{ var_name }}'\""
   register: result
 
-- name: assert output mysql variable name and value
+- name: Assert output mysql variable name and value
   assert:
     that:
       - result is changed
diff --git a/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml b/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml
index dadfb87..def6d8b 100644
--- a/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml
+++ b/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml
@@ -9,7 +9,7 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
   when: tls_enabled
   block:
@@ -26,6 +26,7 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
+        host_all: true
         state: absent
       ignore_errors: yes
 
@@ -33,6 +34,7 @@
       mysql_user:
         <<: *mysql_params
         name: "{{ user_name_1 }}"
+        host: '%'
         password: "{{ user_password_1 }}"
         priv: '*.*:ALL,GRANT'
         tls_requires:
@@ -43,7 +45,7 @@
         variable: '{{ set_name }}'
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
       register: result
@@ -52,19 +54,21 @@
     - assert:
         that:
           - result is failed
-      when: connector_name is search('pymysql')
+      when:
+        - connector_name == 'pymysql'
 
     - assert:
         that:
           - result is succeeded
-      when: connector_name is not search('pymysql')
+      when:
+        - connector_name != 'pymysql'
 
     - name: attempt connection with newly created user ignoring hostname
       mysql_variables:
         variable: '{{ set_name }}'
         login_user: '{{ user_name_1 }}'
         login_password: '{{ user_password_1 }}'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         ca_cert: /tmp/cert.pem
         check_hostname: no
@@ -79,5 +83,5 @@
       mysql_user:
         <<: *mysql_params
         name: '{{ user_name_1 }}'
-        host: 127.0.0.1
+        host_all: true
         state: absent
diff --git a/tests/integration/targets/test_mysql_variables/tasks/mysql_variables.yml b/tests/integration/targets/test_mysql_variables/tasks/mysql_variables.yml
index ed34966..c8ae3e8 100644
--- a/tests/integration/targets/test_mysql_variables/tasks/mysql_variables.yml
+++ b/tests/integration/targets/test_mysql_variables/tasks/mysql_variables.yml
@@ -23,15 +23,11 @@
     mysql_parameters: &mysql_params
       login_user: '{{ mysql_user }}'
       login_password: '{{ mysql_password }}'
-      login_host: 127.0.0.1
+      login_host: '{{ mysql_host }}'
       login_port: '{{ mysql_primary_port }}'
 
   block:
 
-    - name: alias mysql command to include default options
-      set_fact:
-        mysql_command: "mysql -u{{ mysql_user }} -p{{ mysql_password }} -P{{ mysql_primary_port }} --protocol=tcp"
-
     - set_fact:
         set_name: 'version'
 
@@ -151,7 +147,7 @@
     # ============================================================
     # Verify mysql_variable fails when setting an incorrect value (out of range)
     #
-    - name: set mysql variable value to a number out of range
+    - name: Set mysql variable value to a number out of range
       mysql_variables:
         <<: *mysql_params
         variable: max_connect_errors
@@ -160,10 +156,13 @@
       ignore_errors: true
 
     - include: assert_var.yml changed=true output={{ oor_result }} var_name=max_connect_errors var_value=1
-      when: connector_name is not search('pymysql')
+      when:
+        - connector_name == 'mysqlclient'
+        - db_engine == 'mysql'  # mysqlclient returns "changed" with MariaDB
 
     - include: assert_fail_msg.yml output={{ oor_result }}  msg='Truncated incorrect'
-      when: connector_name is search('pymysql')
+      when:
+        - connector_name == 'pymsql'
 
     # ============================================================
     # Verify mysql_variable fails when setting an incorrect value (incorrect type)
@@ -246,7 +245,7 @@
       mysql_variables:
         login_user: '{{ mysql_user }}'
         login_password: 'wrongpassword'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         variable: '{{ set_name }}'
       register: result
@@ -258,7 +257,7 @@
       mysql_variables:
         login_user: '{{ mysql_user }}'
         login_password: 'wrongpassword'
-        login_host: 127.0.0.1
+        login_host: '{{ mysql_host }}'
         login_port: '{{ mysql_primary_port }}'
         variable: '{{ set_name }}'
         value: '{{ set_value }}'
@@ -360,8 +359,8 @@
         - include: assert_var.yml changed=true output={{ result }} var_name={{ set_name }} var_value='{{ def_val }}'
 
       when:
-        - mysql_version is version('8.0', '>=')
-        - install_type == 'mysql'
+        - db_engine == 'mysql'
+        - db_version is version('8.0', '>=')
 
     # Bugfix of https://github.com/ansible/ansible/issues/54239
     # - name: set variable containing dot
diff --git a/tests/integration/test_connection.yml b/tests/integration/test_connection.yml
new file mode 100644
index 0000000..160cfba
--- /dev/null
+++ b/tests/integration/test_connection.yml
@@ -0,0 +1,81 @@
+---
+
+- name: Playbook to test bug to connect to MySQL/MariaDB server
+  hosts: all
+  gather_facts: false
+  vars:
+    mysql_parameters: &mysql_params
+      login_user: '{{ mysql_user }}'
+      login_password: '{{ mysql_password }}'
+      login_host: '{{ mysql_host }}'
+      login_port: '{{ mysql_primary_port }}'
+  tasks:
+
+    # Create default MySQL config file with credentials
+    - name: mysql_info - create default config file
+      template:
+        src: my.cnf.j2
+        dest: /root/.my.cnf
+        mode: '0400'
+
+    # Create non-default MySQL config file with credentials
+    - name: mysql_info - create non-default config file
+      template:
+        src: tests/integration/targets/test_mysql_info/templates/my.cnf.j2
+        dest: /root/non-default_my.cnf
+        mode: '0400'
+
+    ###############
+    # Do tests
+
+    # Access by default cred file
+    - name: mysql_info - collect default cred file
+      mysql_info:
+        login_user: '{{ mysql_user }}'
+        login_host: '{{ mysql_host }}'
+        login_port: '{{ mysql_primary_port }}'
+      register: result
+
+    - assert:
+        that:
+          - result is not changed
+          - db_version in result.version.full
+          - result.settings != {}
+          - result.global_status != {}
+          - result.databases != {}
+          - result.engines != {}
+          - result.users != {}
+
+    # Access by non-default cred file
+    - name: mysql_info - check non-default cred file
+      mysql_info:
+        login_user: '{{ mysql_user }}'
+        login_host: '{{ mysql_host }}'
+        login_port: '{{ mysql_primary_port }}'
+        config_file: /root/non-default_my.cnf
+      register: result
+
+    - assert:
+        that:
+          - result is not changed
+          - result.version != {}
+
+    # Remove cred files
+    - name: mysql_info - remove cred files
+      file:
+        path: '{{ item }}'
+        state: absent
+      with_items:
+        - /root/.my.cnf
+        - /root/non-default_my.cnf
+
+    # Access with password
+    - name: mysql_info - check access with password
+      mysql_info:
+        <<: *mysql_params
+      register: result
+
+    - assert:
+        that:
+          - result is not changed
+          - result.version != {}