diff --git a/_test/mysql.conf.php.dist b/_test/mysql.conf.php.dist
new file mode 100644
index 0000000000000000000000000000000000000000..d72c9886e71a9f73db40f68a919b917cb3e3e5d2
--- /dev/null
+++ b/_test/mysql.conf.php.dist
@@ -0,0 +1,8 @@
+<?php
+/**
+ * This configures the access to a mysql database. The user needs to have permissions
+ * to create and drop databases.
+ */
+$conf['host'] = 'localhost';
+$conf['user'] = 'root';
+$conf['pass'] = '';
diff --git a/lib/plugins/authpdo/_test/mysql.test.php b/lib/plugins/authpdo/_test/mysql.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..a04ccde59c1b6a5caa4af5ec642dd1062bb25736
--- /dev/null
+++ b/lib/plugins/authpdo/_test/mysql.test.php
@@ -0,0 +1,179 @@
+<?php
+
+/**
+ * MySQL tests for the authpdo plugin
+ *
+ * @group plugin_authpdo
+ * @group plugins
+ */
+class mysql_plugin_authpdo_test extends DokuWikiTest {
+
+    protected $host = '';
+    protected $database = 'authpdo_testing';
+    protected $user = '';
+    protected $pass = '';
+
+    public function setUp() {
+        parent::setUp();
+        $configuration = DOKU_UNITTEST . 'mysql.conf.php';
+        if(!file_exists($configuration)) {
+            return;
+        }
+        /** @var $conf array */
+        include $configuration;
+        $this->host = $conf['host'];
+        $this->user = $conf['user'];
+        $this->pass = $conf['pass'];
+    }
+
+    /**
+     * Check if database credentials exist
+     */
+    public function test_requirements() {
+        if(!$this->host || !$this->user) {
+            $this->markTestSkipped("Skipped mysql tests. Missing configuration");
+        }
+    }
+
+    /**
+     * create the database for testing
+     */
+    protected function createDatabase() {
+        $pdo = new PDO(
+            "mysql:dbname=;host={$this->host}", $this->user, $this->pass,
+            array(
+                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes
+            )
+        );
+        $pdo->exec("DROP DATABASE IF EXISTS {$this->database}");
+        $pdo->exec("CREATE DATABASE {$this->database}");
+        $pdo = null;
+    }
+
+    /**
+     * remove the database
+     */
+    protected function dropDatabase() {
+        $pdo = new PDO(
+            "mysql:dbname={$this->database};host={$this->host}", $this->user, $this->pass,
+            array(
+                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes
+            )
+        );
+        $pdo->exec("DROP DATABASE IF EXISTS {$this->database}");
+        $pdo = null;
+    }
+
+    /**
+     * imports a database dump
+     *
+     * @param $file
+     */
+    protected function importDatabase($file) {
+        // connect to database and import dump
+        $pdo = null;
+        $pdo = new PDO(
+            "mysql:dbname={$this->database};host={$this->host}", $this->user, $this->pass,
+            array(
+                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // we want exceptions, not error codes
+            )
+        );
+        $sql = file_get_contents($file);
+        $pdo->exec($sql);
+        $pdo = null;
+    }
+
+    /**
+     * run all the tests with the given user, depending on the capabilities
+     *
+     * @param auth_plugin_authpdo $auth
+     * @param $user
+     */
+    protected function runTests(auth_plugin_authpdo $auth, $user) {
+        global $conf;
+        $info = 'testing ' . $user['user'];
+        $this->assertTrue($auth->success, $info);
+
+        // minimal setup
+        $this->assertTrue($auth->checkPass($user['user'], $user['pass']), $info);
+        $check = $auth->getUserData($user['user']);
+        $this->assertEquals($user['user'], $check['user'], $info);
+        $this->assertEquals($user['name'], $check['name'], $info);
+        $this->assertEquals($user['mail'], $check['mail'], $info);
+        $groups = array_merge($user['grps'], array($conf['defaultgroup']));
+        $this->assertEquals($groups, $check['grps'], $info);
+
+        // modPass
+        if($auth->canDo('modPass')) {
+            $newpass = 'foobar';
+            $ok = $auth->modifyUser($user['user'], array('pass' => $newpass));
+            $this->assertTrue($ok, $info);
+            $this->assertTrue($auth->checkPass($user['user'], $newpass), $info);
+        }
+
+        // modMail
+        if($auth->canDo('modMail')) {
+            $newmail = 'foobar@example.com';
+            $ok = $auth->modifyUser($user['user'], array('mail' => $newmail));
+            $this->assertTrue($ok, $info);
+            $check = $auth->getUserData($user['user']);
+            $this->assertEquals($newmail, $check['mail'], $info);
+        }
+
+        // modName
+        if($auth->canDo('modName')) {
+            $newname = 'FirstName Foobar';
+            $ok = $auth->modifyUser($user['user'], array('name' => $newname));
+            $this->assertTrue($ok, $info);
+            $check = $auth->getUserData($user['user']);
+            $this->assertEquals($newname, $check['name'], $info);
+        }
+
+        // modLogin
+        if($auth->canDo('modLogin')) {
+            $newuser = 'foobar'.$user['user'];
+            $ok = $auth->modifyUser($user['user'], array('user' => $newuser));
+            $this->assertTrue($ok, $info);
+            $check = $auth->getUserData($newuser);
+            $this->assertEquals($newuser, $check['user'], $info);
+        }
+
+    }
+
+    /**
+     * This triggers all the tests based on the dumps and configurations
+     *
+     * @depends test_requirements
+     */
+    public function test_mysql() {
+        global $conf;
+
+        $files = glob(__DIR__ . '/mysql/*.php');
+        foreach($files as $file) {
+            $dump = preg_replace('/\.php$/', '.sql', $file);
+
+            $this->createDatabase();
+            $this->importDatabase($dump);
+
+            // Setup the configuration and initialize a new auth object
+            /** @var $data array */
+            include $file;
+
+            $conf['plugin']['authpdo'] = array();
+            $conf['plugin']['authpdo'] = $data['conf'];
+            $conf['plugin']['authpdo']['dsn'] = "mysql:dbname={$this->database};host={$this->host}";
+            $conf['plugin']['authpdo']['user'] = $this->user;
+            $conf['plugin']['authpdo']['pass'] = $this->pass;
+            $conf['plugin']['authpdo']['debug'] = 1;
+            if($data['passcrypt']) $conf['passcrypt'] = $data['passcrypt'];
+            $auth = new auth_plugin_authpdo();
+
+            foreach($data['users'] as $user) {
+                $this->runTests($auth, $user);
+            }
+
+            $this->dropDatabase();
+        }
+    }
+
+}
diff --git a/lib/plugins/authpdo/_test/mysql/wordpress.php b/lib/plugins/authpdo/_test/mysql/wordpress.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ea2783d471a339fb7b9499a21e677d9bcc94435
--- /dev/null
+++ b/lib/plugins/authpdo/_test/mysql/wordpress.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Basic Wordpress config
+ *
+ * Wordpress has no proper groups. This configures the default access permissions as groups. Better group
+ * support is available through a Wrdpress plugin
+ */
+/** @noinspection SqlResolve */
+$data = array(
+    'passcrypt' => 'pmd5',
+    'conf' => array(
+        'select-user' => '
+            SELECT ID AS uid,
+                   user_login AS user,
+                   display_name AS name,
+                   user_pass AS hash,
+                   user_email AS mail
+              FROM wpvk_users
+             WHERE user_login = :user
+        ',
+        'select-user-groups' => '
+            SELECT CONCAT("group",meta_value) as `group`
+              FROM wpvk_usermeta
+             WHERE user_id = :uid
+               AND meta_key = "wpvk_user_level"
+        ',
+        'select-groups' => '',
+        'insert-user' => '',
+        'delete-user' => '',
+        'list-users' => '',
+        'count-users' => '',
+        'update-user-info' => '
+            UPDATE wpvk_users
+               SET display_name = :name,
+                   user_email = :mail
+             WHERE ID = :uid
+        ',
+        'update-user-login' => '
+            UPDATE wpvk_users
+               SET user_login  = :newlogin
+             WHERE ID = :uid
+        ',
+        'update-user-pass' => '
+            UPDATE wpvk_users
+               SET user_pass = :hash
+             WHERE ID = :uid
+        ',
+        'insert-group' => '',
+        'join-group' => '',
+        'leave-group' => '',
+    ),
+    'users' => array(
+        array(
+            'user' => 'admin',
+            'pass' => 'pass',
+            'name' => 'admin',
+            'mail' => 'admin@example.com',
+            'grps' =>
+                array(
+                    0 => 'group10',
+                ),
+        ),
+        array(
+            'user' => 'test1',
+            'pass' => 'pass',
+            'name' => 'Test1 Subscriber',
+            'mail' => 'test1@example.com',
+            'grps' =>
+                array(
+                    0 => 'group0',
+                ),
+        ),
+        array(
+            'user' => 'test2',
+            'pass' => 'pass',
+            'name' => 'Test2 Contributor',
+            'mail' => 'test2@example.com',
+            'grps' =>
+                array(
+                    0 => 'group1',
+                ),
+        ),
+        array(
+            'user' => 'test3',
+            'pass' => 'pass',
+            'name' => 'Test3 Author',
+            'mail' => 'test3@example.com',
+            'grps' =>
+                array(
+                    0 => 'group2',
+                ),
+        ),
+    ),
+);
diff --git a/lib/plugins/authpdo/_test/mysql/wordpress.sql b/lib/plugins/authpdo/_test/mysql/wordpress.sql
new file mode 100644
index 0000000000000000000000000000000000000000..5f30328b2498419dc1312e68b1c569f24a9a7d83
--- /dev/null
+++ b/lib/plugins/authpdo/_test/mysql/wordpress.sql
@@ -0,0 +1,130 @@
+-- phpMyAdmin SQL Dump
+-- version 4.0.10.7
+-- http://www.phpmyadmin.net
+--
+-- Host: localhost:3306
+-- Generation Time: Feb 10, 2016 at 02:02 PM
+-- Server version: 10.0.23-MariaDB
+-- PHP Version: 5.4.31
+
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+
+--
+-- Database: `dokuwiki_wp240`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `wpvk_usermeta`
+--
+
+CREATE TABLE IF NOT EXISTS `wpvk_usermeta` (
+  `umeta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+  `user_id` bigint(20) unsigned NOT NULL DEFAULT '0',
+  `meta_key` varchar(255) DEFAULT NULL,
+  `meta_value` longtext,
+  PRIMARY KEY (`umeta_id`),
+  KEY `user_id` (`user_id`),
+  KEY `meta_key` (`meta_key`(191))
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=52 ;
+
+--
+-- Dumping data for table `wpvk_usermeta`
+--
+
+INSERT INTO `wpvk_usermeta` (`umeta_id`, `user_id`, `meta_key`, `meta_value`) VALUES
+(1, 1, 'nickname', 'admin'),
+(2, 1, 'first_name', 'First'),
+(3, 1, 'last_name', 'Last'),
+(4, 1, 'description', ''),
+(5, 1, 'rich_editing', 'true'),
+(6, 1, 'comment_shortcuts', 'false'),
+(7, 1, 'admin_color', 'fresh'),
+(8, 1, 'use_ssl', '0'),
+(9, 1, 'show_admin_bar_front', 'true'),
+(10, 1, 'wpvk_capabilities', 'a:1:{s:13:"administrator";b:1;}'),
+(11, 1, 'wpvk_user_level', '10'),
+(12, 1, 'dismissed_wp_pointers', ''),
+(13, 1, 'show_welcome_panel', '1'),
+(14, 1, 'session_tokens', 'a:1:{s:64:"3e9f99a7068bf3fb79f50e111b6ef10f599beb466c27152205d4b89360c5004d";a:4:{s:10:"expiration";i:1456340157;s:2:"ip";s:12:"86.56.56.217";s:2:"ua";s:104:"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.82 Safari/537.36";s:5:"login";i:1455130557;}}'),
+(15, 1, 'wpvk_dashboard_quick_press_last_post_id', '3'),
+(16, 2, 'nickname', 'test1'),
+(17, 2, 'first_name', 'Test1'),
+(18, 2, 'last_name', 'Subscriber'),
+(19, 2, 'description', ''),
+(20, 2, 'rich_editing', 'true'),
+(21, 2, 'comment_shortcuts', 'false'),
+(22, 2, 'admin_color', 'fresh'),
+(23, 2, 'use_ssl', '0'),
+(24, 2, 'show_admin_bar_front', 'true'),
+(25, 2, 'wpvk_capabilities', 'a:1:{s:10:"subscriber";b:1;}'),
+(26, 2, 'wpvk_user_level', '0'),
+(27, 2, 'dismissed_wp_pointers', ''),
+(28, 3, 'nickname', 'test2'),
+(29, 3, 'first_name', 'Test2'),
+(30, 3, 'last_name', 'Contributor'),
+(31, 3, 'description', ''),
+(32, 3, 'rich_editing', 'true'),
+(33, 3, 'comment_shortcuts', 'false'),
+(34, 3, 'admin_color', 'fresh'),
+(35, 3, 'use_ssl', '0'),
+(36, 3, 'show_admin_bar_front', 'true'),
+(37, 3, 'wpvk_capabilities', 'a:1:{s:11:"contributor";b:1;}'),
+(38, 3, 'wpvk_user_level', '1'),
+(39, 3, 'dismissed_wp_pointers', ''),
+(40, 4, 'nickname', 'test3'),
+(41, 4, 'first_name', 'Test3'),
+(42, 4, 'last_name', 'Author'),
+(43, 4, 'description', ''),
+(44, 4, 'rich_editing', 'true'),
+(45, 4, 'comment_shortcuts', 'false'),
+(46, 4, 'admin_color', 'fresh'),
+(47, 4, 'use_ssl', '0'),
+(48, 4, 'show_admin_bar_front', 'true'),
+(49, 4, 'wpvk_capabilities', 'a:1:{s:6:"author";b:1;}'),
+(50, 4, 'wpvk_user_level', '2'),
+(51, 4, 'dismissed_wp_pointers', '');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `wpvk_users`
+--
+
+CREATE TABLE IF NOT EXISTS `wpvk_users` (
+  `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+  `user_login` varchar(60) NOT NULL DEFAULT '',
+  `user_pass` varchar(255) NOT NULL DEFAULT '',
+  `user_nicename` varchar(50) NOT NULL DEFAULT '',
+  `user_email` varchar(100) NOT NULL DEFAULT '',
+  `user_url` varchar(100) NOT NULL DEFAULT '',
+  `user_registered` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+  `user_activation_key` varchar(255) NOT NULL DEFAULT '',
+  `user_status` int(11) NOT NULL DEFAULT '0',
+  `display_name` varchar(250) NOT NULL DEFAULT '',
+  PRIMARY KEY (`ID`),
+  KEY `user_login_key` (`user_login`),
+  KEY `user_nicename` (`user_nicename`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
+
+--
+-- Dumping data for table `wpvk_users`
+--
+
+INSERT INTO `wpvk_users` (`ID`, `user_login`, `user_pass`, `user_nicename`, `user_email`, `user_url`, `user_registered`, `user_activation_key`, `user_status`, `display_name`) VALUES
+(1, 'admin', '$P$BlO2X5nM.djjfsPjOBHz97GHZmpBRr.', 'admin', 'admin@example.com', '', '2016-02-10 18:55:26', '', 0, 'admin'),
+(2, 'test1', '$P$B3BfWySh.ymDeURK0OXMFo4vh4JprO0', 'test1', 'test1@example.com', '', '2016-02-10 18:57:47', '', 0, 'Test1 Subscriber'),
+(3, 'test2', '$P$BMNEUEo5nalKEswryuP69KXEfz8Y.z.', 'test2', 'test2@example.com', '', '2016-02-10 18:58:32', '', 0, 'Test2 Contributor'),
+(4, 'test3', '$P$B2PP3AP6NF/jLO0HYu3xf577rBnp2j.', 'test3', 'test3@example.com', '', '2016-02-10 18:59:19', '', 0, 'Test3 Author');
+
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;