diff --git a/lib/geocoder/lookups/base.rb b/lib/geocoder/lookups/base.rb
index a770f97f11546f5519bab2ca1dc8cc8da97e8e33..7c80494a07050aaa74061c2681ff778d52a64328 100644
--- a/lib/geocoder/lookups/base.rb
+++ b/lib/geocoder/lookups/base.rb
@@ -73,6 +73,16 @@ module Geocoder
         fail
       end
 
+      def query_url_params(query)
+        query.options[:params] || {}
+      end
+
+      def url_query_string(query)
+        hash_to_query(
+          query_url_params(query).reject{ |key,value| value.nil? }
+        )
+      end
+
       ##
       # URL to use for querying the geocoding engine.
       #
diff --git a/lib/geocoder/lookups/bing.rb b/lib/geocoder/lookups/bing.rb
index a5d254c36fd52c85024656aacb300b0aedc2a038..1edb567a8532a4b3ddc8c10b0640e0c1ee2861c9 100644
--- a/lib/geocoder/lookups/bing.rb
+++ b/lib/geocoder/lookups/bing.rb
@@ -21,13 +21,17 @@ module Geocoder::Lookup
       end
     end
 
-    def query_url(query)
-      params = {:key => Geocoder::Configuration.api_key}
-      params[:query] = query.sanitized_text unless query.reverse_geocode?
+    def query_url_params(query)
+      super.merge(
+        :key => Geocoder::Configuration.api_key,
+        :query => query.reverse_geocode? ? nil : query.sanitized_text
+      )
+    end
 
-      base_url = "http://dev.virtualearth.net/REST/v1/Locations"
-      url_tail = query.reverse_geocode? ? "/#{query.sanitized_text}?" : "?"
-      base_url + url_tail + hash_to_query(params)
+    def query_url(query)
+      "http://dev.virtualearth.net/REST/v1/Locations" +
+        (query.reverse_geocode? ? "/#{query.sanitized_text}?" : "?") +
+        url_query_string(query)
     end
   end
 end
diff --git a/lib/geocoder/lookups/geocoder_ca.rb b/lib/geocoder/lookups/geocoder_ca.rb
index 379d0fd40c53a123d74a3b6d08d5f4d6c0a9079a..97ac2721c756fe0e158f7ac51b3106f7bb9af1bb 100644
--- a/lib/geocoder/lookups/geocoder_ca.rb
+++ b/lib/geocoder/lookups/geocoder_ca.rb
@@ -18,13 +18,13 @@ module Geocoder::Lookup
       return []
     end
 
-    def query_url(query)
-      params = {
+    def query_url_params(query)
+      params = super.merge(
         :geoit    => "xml",
         :jsonp    => 1,
         :callback => "test",
         :auth     => Geocoder::Configuration.api_key
-      }
+      )
       if query.reverse_geocode?
         lat,lon = query.coordinates
         params[:latt] = lat
@@ -35,7 +35,11 @@ module Geocoder::Lookup
         params[:locate] = query.sanitized_text
         params[:showpostal] = 1
       end
-      "http://geocoder.ca/?" + hash_to_query(params)
+      params
+    end
+
+    def query_url(query)
+      "http://geocoder.ca/?" + url_query_string(query)
     end
 
     def parse_raw_data(raw_data)
diff --git a/lib/geocoder/lookups/google.rb b/lib/geocoder/lookups/google.rb
index 967294f53c3abfe4728b6710e9121e861069a50f..13bb676351260674d6a7dbc47f469586fac895f3 100644
--- a/lib/geocoder/lookups/google.rb
+++ b/lib/geocoder/lookups/google.rb
@@ -27,7 +27,7 @@ module Geocoder::Lookup
       return []
     end
 
-    def query_url_base_params(query)
+    def query_url_google_params(query)
       params = {
         (query.reverse_geocode? ? :latlng : :address) => query.sanitized_text,
         :sensor => "false",
@@ -39,11 +39,14 @@ module Geocoder::Lookup
       params
     end
 
-    def query_url(query)
-      params = query_url_base_params(query).merge(
+    def query_url_params(query)
+      super.merge(query_url_google_params(query)).merge(
         :key => Geocoder::Configuration.api_key
-      ).reject{ |key, value| value.nil? }
-      "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + hash_to_query(params)
+      )
+    end
+
+    def query_url(query)
+      "#{protocol}://maps.googleapis.com/maps/api/geocode/json?" + url_query_string(query)
     end
   end
 end
diff --git a/lib/geocoder/lookups/google_premier.rb b/lib/geocoder/lookups/google_premier.rb
index 2f1d974c76ccceceac9fdc6f7df6f80dd0193c56..b725b9fb4543aacd07206a7746a92d54f1bcdbf3 100644
--- a/lib/geocoder/lookups/google_premier.rb
+++ b/lib/geocoder/lookups/google_premier.rb
@@ -8,12 +8,16 @@ module Geocoder::Lookup
 
     private # ---------------------------------------------------------------
 
-    def query_url(query)
-      params = query_url_base_params(query).merge(
+    def query_url_params(query)
+      super.merge(query_url_google_params(query)).merge(
+        :key => nil, # don't use param inherited from Google lookup
         :client => Geocoder::Configuration.api_key[1],
         :channel => Geocoder::Configuration.api_key[2]
-      ).reject{ |key, value| value.nil? }
-      path = "/maps/api/geocode/json?#{hash_to_query(params)}"
+      )
+    end
+
+    def query_url(query)
+      path = "/maps/api/geocode/json?" + url_query_string(query)
       "#{protocol}://maps.googleapis.com#{path}&signature=#{sign(path)}"
     end
 
diff --git a/lib/geocoder/lookups/mapquest.rb b/lib/geocoder/lookups/mapquest.rb
index 0b02807cd2c13cc45168259a77e32fac2c8819fe..404bda22eef80bfc0e79593a39df3345f6ef5717 100644
--- a/lib/geocoder/lookups/mapquest.rb
+++ b/lib/geocoder/lookups/mapquest.rb
@@ -8,9 +8,8 @@ module Geocoder::Lookup
     private # ---------------------------------------------------------------
 
     def query_url(query)
-      params = query_url_params(query)
       method = query.reverse_geocode? ? "reverse" : "search"
-      "http://open.mapquestapi.com/#{method}?" + hash_to_query(params)
+      "http://open.mapquestapi.com/#{method}?" + url_query_string(query)
     end
   end
 end
diff --git a/lib/geocoder/lookups/nominatim.rb b/lib/geocoder/lookups/nominatim.rb
index 3a0773690c662ff9755f3309bd5778a48f35b74e..d79f7312650c2d6d3d7df63285c0b6cea5b4bb19 100644
--- a/lib/geocoder/lookups/nominatim.rb
+++ b/lib/geocoder/lookups/nominatim.rb
@@ -16,12 +16,12 @@ module Geocoder::Lookup
     end
 
     def query_url_params(query)
-      params = {
+      params = super.merge(
         :format => "json",
         :polygon => "1",
         :addressdetails => "1",
         :"accept-language" => Geocoder::Configuration.language
-      }
+      )
       if query.reverse_geocode?
         lat,lon = query.coordinates
         params[:lat] = lat
@@ -33,9 +33,8 @@ module Geocoder::Lookup
     end
 
     def query_url(query)
-      params = query_url_params(query)
       method = query.reverse_geocode? ? "reverse" : "search"
-      "http://nominatim.openstreetmap.org/#{method}?" + hash_to_query(params)
+      "http://nominatim.openstreetmap.org/#{method}?" + url_query_string(query)
     end
   end
 end
diff --git a/lib/geocoder/lookups/yahoo.rb b/lib/geocoder/lookups/yahoo.rb
index e240fb4a9361939143c0c9351c818ef2a594bc98..9282f2e970deedc170889f1d5d2043673cf38251 100644
--- a/lib/geocoder/lookups/yahoo.rb
+++ b/lib/geocoder/lookups/yahoo.rb
@@ -20,15 +20,18 @@ module Geocoder::Lookup
       end
     end
 
-    def query_url(query)
-      params = {
+    def query_url_params(query)
+      super.merge(
         :location => query.sanitized_text,
         :flags => "JXTSR",
         :gflags => "AC#{'R' if query.reverse_geocode?}",
         :locale => "#{Geocoder::Configuration.language}_US",
         :appid => Geocoder::Configuration.api_key
-      }
-      "http://where.yahooapis.com/geocode?" + hash_to_query(params)
+      )
+    end
+
+    def query_url(query)
+      "http://where.yahooapis.com/geocode?" + url_query_string(query)
     end
   end
 end
diff --git a/lib/geocoder/lookups/yandex.rb b/lib/geocoder/lookups/yandex.rb
index 11f092d791b39f9576c0380f86d5e492d838a100..9b4f63d6e8104fe422f7d48474e51fba30973bf6 100644
--- a/lib/geocoder/lookups/yandex.rb
+++ b/lib/geocoder/lookups/yandex.rb
@@ -25,19 +25,22 @@ module Geocoder::Lookup
       end
     end
 
-    def query_url(query)
+    def query_url_params(query)
       if query.reverse_geocode?
         q = query.coordinates.reverse.join(",")
       else
         q = query.sanitized_text
       end
-      params = {
+      super.merge(
         :geocode => q,
         :format => "json",
         :plng => "#{Geocoder::Configuration.language}", # supports ru, uk, be
         :key => Geocoder::Configuration.api_key
-      }
-      "http://geocode-maps.yandex.ru/1.x/?" + hash_to_query(params)
+      )
+    end
+
+    def query_url(query)
+      "http://geocode-maps.yandex.ru/1.x/?" + url_query_string(query)
     end
   end
 end
diff --git a/test/services_test.rb b/test/services_test.rb
index 2864588dd465dbb903d4af3eed40211dd0fb89e7..07cb694c728458b88f1ac04ab7654aa11bcf05ac 100644
--- a/test/services_test.rb
+++ b/test/services_test.rb
@@ -4,6 +4,18 @@ require 'test_helper'
 class ServicesTest < Test::Unit::TestCase
 
 
+  def test_query_url_contains_values_in_params_hash
+    Geocoder::Lookup.all_services_except_test.each do |l|
+      next if l == :google_premier # TODO: need to set keys to test
+      next if l == :freegeoip # does not use query string
+      url = Geocoder::Lookup.get(l).send(:query_url, Geocoder::Query.new(
+        "test", :params => {:one_in_the_hand => "two in the bush"}
+      ))
+      assert_match /one_in_the_hand=two\+in\+the\+bush/, url,
+        "Lookup #{l} does not appear to support arbitrary params in URL"
+    end
+  end
+
   # --- Google ---
 
   def test_google_result_components