diff --git a/src/ProxyClient/AbstractVarnishClient.php b/src/ProxyClient/AbstractVarnishClient.php
new file mode 100644
index 00000000..f38c5f5f
--- /dev/null
+++ b/src/ProxyClient/AbstractVarnishClient.php
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the FOSHttpCache package.
+ *
+ * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace FOS\HttpCache\ProxyClient;
+
+use FOS\HttpCache\Exception\InvalidArgumentException;
+
+abstract class AbstractVarnishClient extends AbstractProxyClient
+{
+    const HTTP_HEADER_HOST         = 'X-Host';
+    const HTTP_HEADER_URL          = 'X-Url';
+    const HTTP_HEADER_CONTENT_TYPE = 'X-Content-Type';
+
+    protected function createHostsRegex(array $hosts)
+    {
+        if (!count($hosts)) {
+            throw new InvalidArgumentException('Either supply a list of hosts or null, but not an empty array.');
+        }
+
+        return '^('.join('|', $hosts).')$';
+    }
+}
diff --git a/src/ProxyClient/Varnish.php b/src/ProxyClient/Varnish.php
index b66e4a33..6d891190 100644
--- a/src/ProxyClient/Varnish.php
+++ b/src/ProxyClient/Varnish.php
@@ -11,7 +11,6 @@
 
 namespace FOS\HttpCache\ProxyClient;
 
-use FOS\HttpCache\Exception\InvalidArgumentException;
 use FOS\HttpCache\Exception\MissingHostException;
 use FOS\HttpCache\ProxyClient\Invalidation\BanInterface;
 use FOS\HttpCache\ProxyClient\Invalidation\PurgeInterface;
@@ -27,14 +26,11 @@
  *
  * @author David de Boer <david@driebit.nl>
  */
-class Varnish extends AbstractProxyClient implements BanInterface, PurgeInterface, RefreshInterface, TagsInterface
+class Varnish extends AbstractVarnishClient implements BanInterface, PurgeInterface, RefreshInterface, TagsInterface
 {
     const HTTP_METHOD_BAN          = 'BAN';
     const HTTP_METHOD_PURGE        = 'PURGE';
     const HTTP_METHOD_REFRESH      = 'GET';
-    const HTTP_HEADER_HOST         = 'X-Host';
-    const HTTP_HEADER_URL          = 'X-Url';
-    const HTTP_HEADER_CONTENT_TYPE = 'X-Content-Type';
 
     /**
      * Map of default headers for ban requests with their default values.
@@ -118,10 +114,7 @@ public function ban(array $headers)
     public function banPath($path, $contentType = null, $hosts = null)
     {
         if (is_array($hosts)) {
-            if (!count($hosts)) {
-                throw new InvalidArgumentException('Either supply a list of hosts or null, but not an empty array.');
-            }
-            $hosts = '^('.join('|', $hosts).')$';
+            $hosts = $this->createHostsRegex($hosts);
         }
 
         $headers = [
diff --git a/src/ProxyClient/VarnishAdmin.php b/src/ProxyClient/VarnishAdmin.php
new file mode 100644
index 00000000..0addbc5a
--- /dev/null
+++ b/src/ProxyClient/VarnishAdmin.php
@@ -0,0 +1,195 @@
+<?php
+
+/*
+ * This file is part of the FOSHttpCache package.
+ *
+ * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace FOS\HttpCache\ProxyClient;
+
+use FOS\HttpCache\Exception\ProxyUnreachableException;
+use FOS\HttpCache\ProxyClient\Invalidation\BanInterface;
+use FOS\HttpCache\ProxyClient\VarnishAdmin\Response;
+
+/**
+ * Varnish Admin CLI (also known as Management Port) client
+ */
+class VarnishAdmin extends AbstractVarnishClient implements BanInterface
+{
+    const CLIS_CLOSE = 50;
+    const CLIS_SYNTAX = 100;
+    const CLIS_UNKNOWN = 101;
+    const CLIS_UNIMPL = 102;
+    const CLIS_TOOFEW = 104;
+    const CLIS_TOOMANY = 105;
+    const CLIS_PARAM = 106;
+    const CLIS_AUTH = 107;
+    const CLIS_OK = 200;
+    const CLIS_TRUNCATED = 201;
+    const CLIS_CANT = 300;
+    const CLIS_COMMS = 400;
+
+    const TIMEOUT = 3;
+
+    /**
+     * @var string
+     */
+    private $host;
+
+    /**
+     * @var int
+     */
+    private $port;
+
+    private $connection;
+
+    /**
+     * @var string[]
+     */
+    private $queuedBans = [];
+
+    /**
+     * @var string
+     */
+    private $secret;
+
+    public function __construct($host, $port, $secret = null)
+    {
+        $this->host = $host;
+        $this->port = $port;
+        $this->secret = $secret;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function ban(array $headers)
+    {
+        $mappedHeaders = array_map(
+            function ($name, $value) {
+                return sprintf('obj.http.%s ~ "%s"', $name, $value);
+            },
+            array_keys($headers),
+            $headers
+        );
+
+        $this->queuedBans[] = implode('&&', $mappedHeaders);
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function banPath($path, $contentType = null, $hosts = null)
+    {
+        $ban = sprintf('obj.http.%s ~ "%s"', self::HTTP_HEADER_URL, $path);
+
+        if ($contentType) {
+            $ban .= sprintf(
+                ' && obj.http.content-type ~ "%s"',
+                $contentType
+            );
+        }
+
+        if ($hosts) {
+            $ban .= sprintf(
+                ' && obj.http.%s ~ "%s"',
+                self::HTTP_HEADER_HOST,
+                $this->createHostsRegex($hosts)
+            );
+        }
+
+        $this->queuedBans[] = $ban;
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function flush()
+    {
+        foreach ($this->queuedBans as $ban) {
+            $this->executeCommand('ban', $ban);
+        }
+    }
+
+    private function getConnection()
+    {
+        if ($this->connection === null) {
+            $connection = fsockopen($this->host, $this->port, $errno, $errstr, self::TIMEOUT);
+            if ($connection === false) {
+                throw new ProxyUnreachableException('Unreachable');
+            }
+
+            stream_set_timeout($connection, self::TIMEOUT);
+            $response = $this->read($connection);
+
+            switch ($response->getStatusCode()) {
+                case self::CLIS_AUTH:
+                    $this->authenticate(substr($response->getResponse(), 0, 32), $connection);
+                    break;
+            }
+
+            $this->connection = $connection;
+        }
+
+        return $this->connection;
+    }
+
+    private function read($connection)
+    {
+        while (!feof($connection)) {
+            $line = fgets($connection, 1024);
+            if ($line === false) {
+                throw new ProxyUnreachableException('bla');
+            }
+            if (strlen($line) === 13
+                && preg_match('/^(?P<status>\d{3}) (?P<length>\d+)/', $line, $matches)
+            ) {
+                $response = '';
+                while (!feof($connection) && strlen($response) < $matches['length']) {
+                    $response .= fread($connection, $matches['length']);
+                }
+
+                return new Response($matches['status'], $response);
+            }
+        }
+    }
+
+    private function authenticate($challenge, $connection = null)
+    {
+        $data = sprintf("%1\$s\n%2\$s\n%1\$s\n", $challenge, $this->secret);
+        $hash = hash('sha256', $data);
+
+        $this->executeCommand('auth', $hash, $connection);
+    }
+
+    /**
+     * Execute a command
+     *
+     * @param string    $command
+     * @param string    $param
+     * @param \resource $connection
+     *
+     * @return Response
+     */
+    private function executeCommand($command, $param = null, $connection = null)
+    {
+        $connection = $connection ?: $this->getConnection();
+        $all = sprintf("%s %s\n", $command, $param);
+        fwrite($connection, $all);
+
+        $response = $this->read($connection);
+        if ($response->getStatusCode() !== 200) {
+            throw new \RuntimeException($response->getResponse());
+        }
+
+        return $response;
+    }
+}
diff --git a/src/ProxyClient/VarnishAdmin/Response.php b/src/ProxyClient/VarnishAdmin/Response.php
new file mode 100644
index 00000000..d16f843b
--- /dev/null
+++ b/src/ProxyClient/VarnishAdmin/Response.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace FOS\HttpCache\ProxyClient\VarnishAdmin;
+
+class Response
+{
+    private $statusCode;
+    private $response;
+
+    public function __construct($statusCode, $response)
+    {
+        $this->statusCode = (int) $statusCode;
+        $this->response = $response;
+    }
+
+    /**
+     * @return int
+     */
+    public function getStatusCode()
+    {
+        return $this->statusCode;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getResponse()
+    {
+        return $this->response;
+    }
+}
diff --git a/src/ProxyClient/VarnishAdminMultiple.php b/src/ProxyClient/VarnishAdminMultiple.php
new file mode 100644
index 00000000..4ed962e3
--- /dev/null
+++ b/src/ProxyClient/VarnishAdminMultiple.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace FOS\HttpCache\ProxyClient;
+
+class VarnishAdminMultiple
+{
+    public function __construct($servers)
+    {
+
+    }
+}
diff --git a/src/Test/Proxy/VarnishProxy.php b/src/Test/Proxy/VarnishProxy.php
index 0ceaef2b..5a148ee1 100644
--- a/src/Test/Proxy/VarnishProxy.php
+++ b/src/Test/Proxy/VarnishProxy.php
@@ -47,7 +47,7 @@ public function start()
             '-f', $this->getConfigFile(),
             '-n', $this->getCacheDir(),
             '-p', 'vcl_dir=' . $this->getConfigDir(),
-
+            '-S', realpath('./tests/Functional/Fixtures/secret'),
             '-P', $this->pid,
         ];
         if ($this->getAllowInlineC()) {
diff --git a/tests/Functional/Fixtures/BanTest.php b/tests/Functional/Fixtures/BanTest.php
new file mode 100644
index 00000000..f58838d1
--- /dev/null
+++ b/tests/Functional/Fixtures/BanTest.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace FOS\HttpCache\Tests\Functional\Fixtures;
+
+trait BanTest
+{
+    public function testBanAll()
+    {
+        $this->assertMiss($this->getResponse('/cache.php'));
+        $this->assertHit($this->getResponse('/cache.php'));
+
+        $this->assertMiss($this->getResponse('/json.php'));
+        $this->assertHit($this->getResponse('/json.php'));
+
+        $this->getProxyClient()->ban(['X-Url' => '.*'])->flush();
+
+        $this->assertMiss($this->getResponse('/cache.php'));
+        $this->assertMiss($this->getResponse('/json.php'));
+    }
+
+    public function testBanHost()
+    {
+        $this->assertMiss($this->getResponse('/cache.php'));
+        $this->assertHit($this->getResponse('/cache.php'));
+
+        $this->getProxyClient()->ban(['X-Host' => 'wrong-host.lo'])->flush();
+        $this->assertHit($this->getResponse('/cache.php'));
+
+        $this->getProxyClient()->ban(['X-Host' => $this->getHostname()])->flush();
+        $this->assertMiss($this->getResponse('/cache.php'));
+    }
+
+    public function testBanPathAll()
+    {
+        $this->assertMiss($this->getResponse('/cache.php'));
+        $this->assertHit($this->getResponse('/cache.php'));
+
+        $this->assertMiss($this->getResponse('/json.php'));
+        $this->assertHit($this->getResponse('/json.php'));
+
+        $this->getProxyClient()->banPath('.*')->flush();
+        $this->assertMiss($this->getResponse('/cache.php'));
+        $this->assertMiss($this->getResponse('/json.php'));
+    }
+
+    public function testBanPathContentType()
+    {
+        $this->assertMiss($this->getResponse('/cache.php'));
+        $this->assertHit($this->getResponse('/cache.php'));
+
+        $this->assertMiss($this->getResponse('/json.php'));
+        $this->assertHit($this->getResponse('/json.php'));
+
+        $this->getProxyClient()->banPath('.*', 'text/html')->flush();
+        $this->assertMiss($this->getResponse('/cache.php'));
+        $this->assertHit($this->getResponse('/json.php'));
+    }
+}
diff --git a/tests/Functional/Fixtures/secret b/tests/Functional/Fixtures/secret
new file mode 100755
index 00000000..366bbcc1
--- /dev/null
+++ b/tests/Functional/Fixtures/secret
@@ -0,0 +1 @@
+fos
diff --git a/tests/Functional/ProxyClient/VarnishAdminTest.php b/tests/Functional/ProxyClient/VarnishAdminTest.php
new file mode 100644
index 00000000..1cd8f93c
--- /dev/null
+++ b/tests/Functional/ProxyClient/VarnishAdminTest.php
@@ -0,0 +1,39 @@
+<?php
+
+/*
+ * This file is part of the FOSHttpCache package.
+ *
+ * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace FOS\HttpCache\Tests\Functional\ProxyClient;
+
+use FOS\HttpCache\ProxyClient\VarnishAdmin;
+use FOS\HttpCache\Test\VarnishTestCase;
+use FOS\HttpCache\Tests\Functional\Fixtures\BanTest;
+
+class VarnishAdminTest extends VarnishTestCase
+{
+    use BanTest;
+
+    /**
+     * Get Varnish admin proxy client
+     *
+     * @return VarnishAdmin
+     */
+    protected function getProxyClient()
+    {
+        if (null === $this->proxyClient) {
+            $this->proxyClient = new VarnishAdmin(
+                '127.0.0.1',
+                $this->getProxy()->getManagementPort(),
+                'fos'
+            );
+        }
+
+        return $this->proxyClient;
+    }
+}
diff --git a/tests/Functional/Varnish/VarnishProxyClientTest.php b/tests/Functional/Varnish/VarnishProxyClientTest.php
index fc68261e..705842b4 100644
--- a/tests/Functional/Varnish/VarnishProxyClientTest.php
+++ b/tests/Functional/Varnish/VarnishProxyClientTest.php
@@ -13,6 +13,7 @@
 
 use FOS\HttpCache\ProxyClient\Varnish;
 use FOS\HttpCache\Test\VarnishTestCase;
+use FOS\HttpCache\Tests\Functional\Fixtures\BanTest;
 
 /**
  * @group webserver
@@ -20,57 +21,7 @@
  */
 class VarnishProxyClientTest extends VarnishTestCase
 {
-    public function testBanAll()
-    {
-        $this->assertMiss($this->getResponse('/cache.php'));
-        $this->assertHit($this->getResponse('/cache.php'));
-
-        $this->assertMiss($this->getResponse('/json.php'));
-        $this->assertHit($this->getResponse('/json.php'));
-
-        $this->getProxyClient()->ban([Varnish::HTTP_HEADER_URL => '.*'])->flush();
-
-        $this->assertMiss($this->getResponse('/cache.php'));
-        $this->assertMiss($this->getResponse('/json.php'));
-    }
-
-    public function testBanHost()
-    {
-        $this->assertMiss($this->getResponse('/cache.php'));
-        $this->assertHit($this->getResponse('/cache.php'));
-
-        $this->getProxyClient()->ban([Varnish::HTTP_HEADER_HOST => 'wrong-host.lo'])->flush();
-        $this->assertHit($this->getResponse('/cache.php'));
-
-        $this->getProxyClient()->ban([Varnish::HTTP_HEADER_HOST => $this->getHostname()])->flush();
-        $this->assertMiss($this->getResponse('/cache.php'));
-    }
-
-    public function testBanPathAll()
-    {
-        $this->assertMiss($this->getResponse('/cache.php'));
-        $this->assertHit($this->getResponse('/cache.php'));
-
-        $this->assertMiss($this->getResponse('/json.php'));
-        $this->assertHit($this->getResponse('/json.php'));
-
-        $this->getProxyClient()->banPath('.*')->flush();
-        $this->assertMiss($this->getResponse('/cache.php'));
-        $this->assertMiss($this->getResponse('/json.php'));
-    }
-
-    public function testBanPathContentType()
-    {
-        $this->assertMiss($this->getResponse('/cache.php'));
-        $this->assertHit($this->getResponse('/cache.php'));
-
-        $this->assertMiss($this->getResponse('/json.php'));
-        $this->assertHit($this->getResponse('/json.php'));
-
-        $this->getProxyClient()->banPath('.*', 'text/html')->flush();
-        $this->assertMiss($this->getResponse('/cache.php'));
-        $this->assertHit($this->getResponse('/json.php'));
-    }
+    use BanTest;
 
     public function testPurge()
     {
diff --git a/tests/Unit/Test/Proxy/VarnishProxyTest.php b/tests/Unit/Test/Proxy/VarnishProxyTest.php
index 461b50c6..415599bf 100644
--- a/tests/Unit/Test/Proxy/VarnishProxyTest.php
+++ b/tests/Unit/Test/Proxy/VarnishProxyTest.php
@@ -42,6 +42,7 @@ public function testStart()
                 '-f', 'config.vcl',
                 '-n', '/tmp/cache/dir',
                 '-p', 'vcl_dir=/my/varnish/dir',
+                '-S', realpath('./tests/Functional/Fixtures/secret'),
                 '-P', '/tmp/foshttpcache-varnish.pid',
             ],
             $proxy->arguments