diff --git a/Godeps b/Godeps
index a4f2725a2e4e7b1082009116ee98617d9982b5b6..aa4a5b0e8005d3e745cf98ce6df450a3fb5488f3 100644
--- a/Godeps
+++ b/Godeps
@@ -59,8 +59,10 @@ github.com/zensqlmonitor/go-mssqldb ffe5510c6fa5e15e6d983210ab501c815b56b363
 golang.org/x/crypto dc137beb6cce2043eb6b5f223ab8bf51c32459f4
 golang.org/x/net f2499483f923065a842d38eb4c7f1927e6fc6e6d
 golang.org/x/text 506f9d5c962f284575e88337e7d9296d27e729d3
+gopkg.in/asn1-ber.v1 4e86f4367175e39f69d9358a5f17b4dda270378d
 gopkg.in/fatih/pool.v2 6e328e67893eb46323ad06f0e92cb9536babbabc
 gopkg.in/gorethink/gorethink.v3 7ab832f7b65573104a555d84a27992ae9ea1f659
+gopkg.in/ldap.v2 8168ee085ee43257585e50c6441aadf54ecb2c9f
 gopkg.in/mgo.v2 3f83fa5005286a7fe593b055f0d7771a7dce4655
 gopkg.in/olivere/elastic.v5 3113f9b9ad37509fe5f8a0e5e91c96fdc4435e26
 gopkg.in/yaml.v2 4c78c975fe7c825c6d1466c42be594d1d6f3aba6
diff --git a/Makefile b/Makefile
index a22d2bf1a4c2793128202b5665dde3f80aa97a23..17a947f56087779f9c4ec389600fdba553bd72d3 100644
--- a/Makefile
+++ b/Makefile
@@ -70,6 +70,11 @@ docker-run:
 	docker run --name mqtt -p "1883:1883" -d ncarlier/mqtt
 	docker run --name riemann -p "5555:5555" -d stealthly/docker-riemann
 	docker run --name nats -p "4222:4222" -d nats
+	docker run --name openldap \
+		-e SLAPD_CONFIG_ROOTDN="cn=manager,cn=config" \
+		-e SLAPD_CONFIG_ROOTPW="secret" \
+		-p "389:389" -p "636:636" \
+		-d cobaugh/openldap-alpine
 
 # Run docker containers necessary for CircleCI unit tests
 docker-run-circle:
@@ -88,11 +93,16 @@ docker-run-circle:
 	docker run --name mqtt -p "1883:1883" -d ncarlier/mqtt
 	docker run --name riemann -p "5555:5555" -d stealthly/docker-riemann
 	docker run --name nats -p "4222:4222" -d nats
+	docker run --name openldap \
+		-e SLAPD_CONFIG_ROOTDN="cn=manager,cn=config" \
+		-e SLAPD_CONFIG_ROOTPW="secret" \
+		-p "389:389" -p "636:636" \
+		-d cobaugh/openldap-alpine
 
 # Kill all docker containers, ignore errors
 docker-kill:
-	-docker kill nsq aerospike redis rabbitmq postgres memcached mysql zookeeper kafka mqtt riemann nats elasticsearch
-	-docker rm nsq aerospike redis rabbitmq postgres memcached mysql zookeeper kafka mqtt riemann nats elasticsearch
+	-docker kill nsq aerospike redis rabbitmq postgres memcached mysql zookeeper kafka mqtt riemann nats elasticsearch openldap
+	-docker rm nsq aerospike redis rabbitmq postgres memcached mysql zookeeper kafka mqtt riemann nats elasticsearch openldap
 
 # Run full unit tests using docker containers (includes setup and teardown)
 test: vet docker-kill docker-run
diff --git a/docs/LICENSE_OF_DEPENDENCIES.md b/docs/LICENSE_OF_DEPENDENCIES.md
index 72663069f9edfe9ab2377900372ec9ea4197edfb..da031220100be910109390bb0733ef3b0ac82ea3 100644
--- a/docs/LICENSE_OF_DEPENDENCIES.md
+++ b/docs/LICENSE_OF_DEPENDENCIES.md
@@ -76,8 +76,10 @@ works:
 - golang.org/x/crypto [BSD](https://github.com/golang/crypto/blob/master/LICENSE)
 - golang.org/x/net [BSD](https://go.googlesource.com/net/+/master/LICENSE)
 - golang.org/x/text [BSD](https://go.googlesource.com/text/+/master/LICENSE)
+- gopkg.in/asn1-ber.v1 [MIT](https://github.com/go-asn1-ber/asn1-ber/blob/v1.2/LICENSE)
 - gopkg.in/dancannon/gorethink.v1 [APACHE](https://github.com/dancannon/gorethink/blob/v1.1.2/LICENSE)
 - gopkg.in/fatih/pool.v2 [MIT](https://github.com/fatih/pool/blob/v2.0.0/LICENSE)
+- gopkg.in/ldap.v2 [MIT](https://github.com/go-ldap/ldap/blob/v2.5.0/LICENSE)
 - gopkg.in/mgo.v2 [BSD](https://github.com/go-mgo/mgo/blob/v2/LICENSE)
 - gopkg.in/olivere/elastic.v5 [MIT](https://github.com/olivere/elastic/blob/v5.0.38/LICENSE)
 - gopkg.in/yaml.v2 [APACHE](https://github.com/go-yaml/yaml/blob/v2/LICENSE)
diff --git a/plugins/inputs/all/all.go b/plugins/inputs/all/all.go
index 9bc7afaff133720d9b2054325d58c054629ef2a7..0a68235b8e6f19db3f86e23f62f656652b47e16a 100644
--- a/plugins/inputs/all/all.go
+++ b/plugins/inputs/all/all.go
@@ -57,6 +57,7 @@ import (
 	_ "github.com/influxdata/telegraf/plugins/inputs/nsq_consumer"
 	_ "github.com/influxdata/telegraf/plugins/inputs/nstat"
 	_ "github.com/influxdata/telegraf/plugins/inputs/ntpq"
+	_ "github.com/influxdata/telegraf/plugins/inputs/openldap"
 	_ "github.com/influxdata/telegraf/plugins/inputs/passenger"
 	_ "github.com/influxdata/telegraf/plugins/inputs/phpfpm"
 	_ "github.com/influxdata/telegraf/plugins/inputs/ping"
diff --git a/plugins/inputs/openldap/README.md b/plugins/inputs/openldap/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a57aabb84b7c40fcbe48b64220896cb8060177f9
--- /dev/null
+++ b/plugins/inputs/openldap/README.md
@@ -0,0 +1,82 @@
+# Openldap Input Plugin
+
+This plugin gathers metrics from OpenLDAP's cn=Monitor backend.
+
+### Configuration:
+
+```toml
+[[inputs.openldap]]
+  host = "localhost"
+  port = 389
+
+  # ldaps, starttls, or no encryption. default is an empty string, disabling all encryption.
+  # note that port will likely need to be changed to 636 for ldaps
+  # valid options: "" | "starttls" | "ldaps"
+  ssl = ""
+
+  # skip peer certificate verification. Default is false.
+  insecure_skip_verify = false
+
+  # Path to PEM-encoded Root certificate to use to verify server certificate
+  ssl_ca = "/etc/ssl/certs.pem"
+
+  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.
+  bind_dn = ""
+  bind_password = ""
+```
+
+### Measurements & Fields:
+
+All **monitorCounter**, **monitorOpInitiated**, and **monitorOpCompleted** attributes are gathered based on this LDAP query:
+
+```(|(objectClass=monitorCounterObject)(objectClass=monitorOperation))```
+
+Metric names are based on their entry DN.
+
+Metrics for the **monitorOp*** attributes have **_initiated** and **_completed** added to the base name.
+
+An OpenLDAP 2.4 server will provide these metrics:
+
+- openldap
+	- max_file_descriptors_connections
+	- current_connections
+	- total_connections
+	- abandon_operations_completed
+	- abandon_operations_initiated
+	- add_operations_completed
+	- add_operations_initiated
+	- bind_operations_completed
+	- bind_operations_initiated
+	- compare_operations_completed
+	- compare_operations_initiated
+	- delete_operations_completed
+	- delete_operations_initiated
+	- extended_operations_completed
+	- extended_operations_initiated
+	- modify_operations_completed
+	- modify_operations_initiated
+	- modrdn_operations_completed
+	- modrdn_operations_initiated
+	- search_operations_completed
+	- search_operations_initiated
+	- unbind_operations_completed
+	- unbind_operations_initiated
+	- bytes_statistics
+	- entries_statistics
+	- pdu_statistics
+	- referrals_statistics
+	- read_waiters
+	- write_waiters
+
+### Tags:
+
+- server= # value from config
+- port= # value from config
+
+### Example Output:
+
+```
+$ telegraf -config telegraf.conf -input-filter openldap -test --debug
+* Plugin: inputs.openldap, Collection 1
+> openldap,server=localhost,port=389,host=zirzla search_operations_completed=2i,delete_operations_completed=0i,read_waiters=1i,total_connections=1004i,bind_operations_completed=3i,unbind_operations_completed=3i,referrals_statistics=0i,current_connections=1i,bind_operations_initiated=3i,compare_operations_completed=0i,add_operations_completed=2i,delete_operations_initiated=0i,unbind_operations_initiated=3i,search_operations_initiated=3i,add_operations_initiated=2i,max_file_descriptors_connections=4096i,abandon_operations_initiated=0i,write_waiters=0i,modrdn_operations_completed=0i,abandon_operations_completed=0i,pdu_statistics=23i,modify_operations_initiated=0i,bytes_statistics=1660i,entries_statistics=17i,compare_operations_initiated=0i,modrdn_operations_initiated=0i,extended_operations_completed=0i,modify_operations_completed=0i,extended_operations_initiated=0i 1499990455000000000
+```
diff --git a/plugins/inputs/openldap/openldap.go b/plugins/inputs/openldap/openldap.go
new file mode 100644
index 0000000000000000000000000000000000000000..a70cfd13a93474414548244bae360844cd8f25a2
--- /dev/null
+++ b/plugins/inputs/openldap/openldap.go
@@ -0,0 +1,178 @@
+package openldap
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+
+	"gopkg.in/ldap.v2"
+
+	"github.com/influxdata/telegraf"
+	"github.com/influxdata/telegraf/internal"
+	"github.com/influxdata/telegraf/plugins/inputs"
+)
+
+type Openldap struct {
+	Host               string
+	Port               int
+	Ssl                string
+	InsecureSkipVerify bool
+	SslCa              string
+	BindDn             string
+	BindPassword       string
+}
+
+const sampleConfig string = `
+  host = "localhost"
+  port = 389
+
+  # ldaps, starttls, or no encryption. default is an empty string, disabling all encryption.
+  # note that port will likely need to be changed to 636 for ldaps
+  # valid options: "" | "starttls" | "ldaps"
+  ssl = ""
+
+  # skip peer certificate verification. Default is false.
+  insecure_skip_verify = false
+
+  # Path to PEM-encoded Root certificate to use to verify server certificate
+  ssl_ca = "/etc/ssl/certs.pem"
+
+  # dn/password to bind with. If bind_dn is empty, an anonymous bind is performed.
+  bind_dn = ""
+  bind_password = ""
+`
+
+var searchBase = "cn=Monitor"
+var searchFilter = "(|(objectClass=monitorCounterObject)(objectClass=monitorOperation))"
+var searchAttrs = []string{"monitorCounter", "monitorOpInitiated", "monitorOpCompleted"}
+var attrTranslate = map[string]string{
+	"monitorCounter":     "",
+	"monitorOpInitiated": "_initiated",
+	"monitorOpCompleted": "_completed",
+}
+
+func (o *Openldap) SampleConfig() string {
+	return sampleConfig
+}
+
+func (o *Openldap) Description() string {
+	return "OpenLDAP cn=Monitor plugin"
+}
+
+// return an initialized Openldap
+func NewOpenldap() *Openldap {
+	return &Openldap{
+		Host:               "localhost",
+		Port:               389,
+		Ssl:                "",
+		InsecureSkipVerify: false,
+		SslCa:              "",
+		BindDn:             "",
+		BindPassword:       "",
+	}
+}
+
+// gather metrics
+func (o *Openldap) Gather(acc telegraf.Accumulator) error {
+	var err error
+	var l *ldap.Conn
+	if o.Ssl != "" {
+		// build tls config
+		tlsConfig, err := internal.GetTLSConfig("", "", o.SslCa, o.InsecureSkipVerify)
+		if err != nil {
+			acc.AddError(err)
+			return nil
+		}
+		if o.Ssl == "ldaps" {
+			l, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", o.Host, o.Port), tlsConfig)
+			if err != nil {
+				acc.AddError(err)
+				return nil
+			}
+		} else if o.Ssl == "starttls" {
+			l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", o.Host, o.Port))
+			if err != nil {
+				acc.AddError(err)
+				return nil
+			}
+			err = l.StartTLS(tlsConfig)
+		} else {
+			acc.AddError(fmt.Errorf("Invalid setting for ssl: %s", o.Ssl))
+			return nil
+		}
+	} else {
+		l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", o.Host, o.Port))
+	}
+
+	if err != nil {
+		acc.AddError(err)
+		return nil
+	}
+	defer l.Close()
+
+	// username/password bind
+	if o.BindDn != "" && o.BindPassword != "" {
+		err = l.Bind(o.BindDn, o.BindPassword)
+		if err != nil {
+			acc.AddError(err)
+			return nil
+		}
+	}
+
+	searchRequest := ldap.NewSearchRequest(
+		searchBase,
+		ldap.ScopeWholeSubtree,
+		ldap.NeverDerefAliases,
+		0,
+		0,
+		false,
+		searchFilter,
+		searchAttrs,
+		nil,
+	)
+
+	sr, err := l.Search(searchRequest)
+	if err != nil {
+		acc.AddError(err)
+		return nil
+	}
+
+	gatherSearchResult(sr, o, acc)
+
+	return nil
+}
+
+func gatherSearchResult(sr *ldap.SearchResult, o *Openldap, acc telegraf.Accumulator) {
+	fields := map[string]interface{}{}
+	tags := map[string]string{
+		"server": o.Host,
+		"port":   strconv.Itoa(o.Port),
+	}
+	for _, entry := range sr.Entries {
+		metricName := dnToMetric(entry.DN, searchBase)
+		for _, attr := range entry.Attributes {
+			if len(attr.Values[0]) >= 1 {
+				if v, err := strconv.ParseInt(attr.Values[0], 10, 64); err == nil {
+					fields[metricName+attrTranslate[attr.Name]] = v
+				}
+			}
+		}
+	}
+	acc.AddFields("openldap", fields, tags)
+	return
+}
+
+// Convert a DN to metric name, eg cn=Read,cn=Waiters,cn=Monitor to read_waiters
+func dnToMetric(dn, searchBase string) string {
+	metricName := strings.Trim(dn, " ")
+	metricName = strings.Replace(metricName, " ", "_", -1)
+	metricName = strings.ToLower(metricName)
+	metricName = strings.TrimPrefix(metricName, "cn=")
+	metricName = strings.Replace(metricName, strings.ToLower(searchBase), "", -1)
+	metricName = strings.Replace(metricName, "cn=", "_", -1)
+	return strings.Replace(metricName, ",", "", -1)
+}
+
+func init() {
+	inputs.Add("openldap", func() telegraf.Input { return NewOpenldap() })
+}
diff --git a/plugins/inputs/openldap/openldap_test.go b/plugins/inputs/openldap/openldap_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..489ef863632834fc5830b3fc95d6c51dda5bacc7
--- /dev/null
+++ b/plugins/inputs/openldap/openldap_test.go
@@ -0,0 +1,150 @@
+package openldap
+
+import (
+	"gopkg.in/ldap.v2"
+	"strconv"
+	"testing"
+
+	"github.com/influxdata/telegraf/testutil"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestOpenldapMockResult(t *testing.T) {
+	var acc testutil.Accumulator
+
+	mockSearchResult := ldap.SearchResult{
+		Entries: []*ldap.Entry{
+			{
+				DN:         "cn=Total,cn=Connections,cn=Monitor",
+				Attributes: []*ldap.EntryAttribute{{Name: "monitorCounter", Values: []string{"1"}}},
+			},
+		},
+		Referrals: []string{},
+		Controls:  []ldap.Control{},
+	}
+
+	o := &Openldap{
+		Host: "localhost",
+		Port: 389,
+	}
+
+	gatherSearchResult(&mockSearchResult, o, &acc)
+	commonTests(t, o, &acc)
+}
+
+func TestOpenldapNoConnection(t *testing.T) {
+	if testing.Short() {
+		t.Skip("Skipping integration test in short mode")
+	}
+
+	o := &Openldap{
+		Host: "nosuchhost",
+		Port: 389,
+	}
+
+	var acc testutil.Accumulator
+	err := o.Gather(&acc)
+	require.NoError(t, err)        // test that we didn't return an error
+	assert.Zero(t, acc.NFields())  // test that we didn't return any fields
+	assert.NotEmpty(t, acc.Errors) // test that we set an error
+}
+
+func TestOpenldapGeneratesMetrics(t *testing.T) {
+	if testing.Short() {
+		t.Skip("Skipping integration test in short mode")
+	}
+
+	o := &Openldap{
+		Host: testutil.GetLocalHost(),
+		Port: 389,
+	}
+
+	var acc testutil.Accumulator
+	err := o.Gather(&acc)
+	require.NoError(t, err)
+	commonTests(t, o, &acc)
+}
+
+func TestOpenldapStartTLS(t *testing.T) {
+	if testing.Short() {
+		t.Skip("Skipping integration test in short mode")
+	}
+
+	o := &Openldap{
+		Host:               testutil.GetLocalHost(),
+		Port:               389,
+		Ssl:                "starttls",
+		InsecureSkipVerify: true,
+	}
+
+	var acc testutil.Accumulator
+	err := o.Gather(&acc)
+	require.NoError(t, err)
+	commonTests(t, o, &acc)
+}
+
+func TestOpenldapLDAPS(t *testing.T) {
+	if testing.Short() {
+		t.Skip("Skipping integration test in short mode")
+	}
+
+	o := &Openldap{
+		Host:               testutil.GetLocalHost(),
+		Port:               636,
+		Ssl:                "ldaps",
+		InsecureSkipVerify: true,
+	}
+
+	var acc testutil.Accumulator
+	err := o.Gather(&acc)
+	require.NoError(t, err)
+	commonTests(t, o, &acc)
+}
+
+func TestOpenldapInvalidSSL(t *testing.T) {
+	if testing.Short() {
+		t.Skip("Skipping integration test in short mode")
+	}
+
+	o := &Openldap{
+		Host:               testutil.GetLocalHost(),
+		Port:               636,
+		Ssl:                "invalid",
+		InsecureSkipVerify: true,
+	}
+
+	var acc testutil.Accumulator
+	err := o.Gather(&acc)
+	require.NoError(t, err)        // test that we didn't return an error
+	assert.Zero(t, acc.NFields())  // test that we didn't return any fields
+	assert.NotEmpty(t, acc.Errors) // test that we set an error
+}
+
+func TestOpenldapBind(t *testing.T) {
+	if testing.Short() {
+		t.Skip("Skipping integration test in short mode")
+	}
+
+	o := &Openldap{
+		Host:               testutil.GetLocalHost(),
+		Port:               389,
+		Ssl:                "",
+		InsecureSkipVerify: true,
+		BindDn:             "cn=manager,cn=config",
+		BindPassword:       "secret",
+	}
+
+	var acc testutil.Accumulator
+	err := o.Gather(&acc)
+	require.NoError(t, err)
+	commonTests(t, o, &acc)
+}
+
+func commonTests(t *testing.T, o *Openldap, acc *testutil.Accumulator) {
+	assert.Empty(t, acc.Errors, "accumulator had no errors")
+	assert.True(t, acc.HasMeasurement("openldap"), "Has a measurement called 'openldap'")
+	assert.Equal(t, o.Host, acc.TagValue("openldap", "server"), "Has a tag value of server=o.Host")
+	assert.Equal(t, strconv.Itoa(o.Port), acc.TagValue("openldap", "port"), "Has a tag value of port=o.Port")
+	assert.True(t, acc.HasInt64Field("openldap", "total_connections"), "Has an integer field called total_connections")
+}