function Client(options) {
  assert.ok(options);

  EventEmitter.call(this, options);

  var self = this;
  var _url;
  if (options.url)
    _url = url.parse(options.url);
  this.host = _url ? _url.hostname : undefined;
  this.port = _url ? _url.port : false;
  this.secure = _url ? _url.secure : false;
  this.url = _url;
  this.tlsOptions = options.tlsOptions;
  this.socketPath = options.socketPath || false;

  this.log = options.log.child({clazz: 'Client'}, true);

  this.timeout = parseInt((options.timeout || 0), 10);
  this.connectTimeout = parseInt((options.connectTimeout || 0), 10);
  this.idleTimeout = parseInt((options.idleTimeout || 0), 10);
  if (options.reconnect) {
    // Fall back to defaults if options.reconnect === true
    var rOpts = (typeof (options.reconnect) === 'object') ?
      options.reconnect : {};
    this.reconnect = {
      initialDelay: parseInt(rOpts.initialDelay || 100, 10),
      maxDelay: parseInt(rOpts.maxDelay || 10000, 10),
      failAfter: parseInt(rOpts.failAfter, 10) || Infinity
    };
  }
  this.strictDN = (options.strictDN !== undefined) ? options.strictDN : true;

  this.queue = new RequestQueue({
    size: parseInt((options.queueSize || 0), 10),
    timeout: parseInt((options.queueTimeout || 0), 10)
  });
  if (options.queueDisable) {
    this.queue.freeze();
  }

  // Implicitly configure setup action to bind the client if bindDN and
  // bindCredentials are passed in.  This will more closely mimic PooledClient
  // auto-login behavior.
  if (options.bindDN !== undefined &&
      options.bindCredentials !== undefined) {
    this.on('setup', function (clt, cb) {
      clt.bind(options.bindDN, options.bindCredentials, function (err) {
        if (err) {
          self.emit('error', err);
        }
        cb(err);
      });
    });
  }

  this._socket = null;
  this.connected = false;
  this.connect();
}